Lês datasheets 2: SPI op STM32; PWM, timers en interrupts op STM8
В earste diel Ik besocht te fertellen hobby elektroanika yngenieurs dy't opgroeid út Arduino broek hoe en wêrom se moatte lêze datasheets en oare dokumintaasje foar microcontrollers. De tekst blykte grut te wêzen, dat ik haw tasein praktyske foarbylden yn in apart artikel sjen te litten. No, hy neamde himsels in molke paddestoel...
Hjoed sil ik jo sjen litte hoe't jo gegevensblêden brûke om frij ienfâldich, mar nedich foar in protte projekten, taken op STM32 (Blue Pill) en STM8-controllers op te lossen. Alle demo-projekten binne wijd oan myn favorite LED's, wy sille se yn grutte hoemannichten ljochtsje, wêrfoar wy allerhanne nijsgjirrige perifeare apparaten moatte brûke.
De tekst bleek wer enoarm te wêzen, dus foar it gemak meitsje ik de ynhâld:
Disclaimer: ik bin gjin yngenieur, ik pretend net te hawwen djippe kennis yn elektroanika, it artikel is bedoeld foar amateurs lykas my. Eins haw ik mysels twa jier lyn beskôge as de doelgroep. As immen my doe ferteld hie dat datablêden op in ûnbekende chip net skriklik wiene om te lêzen, dan hie ik net in protte tiid bestege oan it sykjen nei guon stikken koade op it ynternet en it útfine fan krukken mei skjirre en plakband.
De fokus fan dit artikel is op gegevensblêden, net op projekten, sadat de koade miskien net heul kreas en faak krap is. De projekten sels binne hiel ienfâldich, hoewol geskikt foar in earste kunde mei de nije chip.
Ik hoopje dat myn artikel immen sil helpe yn in ferlykber stadium fan ûnderdompeling yn 'e hobby.
STM32
16 LED's mei DM634 en SPI
In lyts projekt mei help fan Blue Pill (STM32F103C8T6) en DM634 LED driver. Mei help fan datasheets, wy sille útfine de bestjoerder, STM IO havens en konfigurearje SPI.
DM634
Taiwaneeske chip mei 16 16-bit PWM útgongen, kin wurde ferbûn yn keatlingen. It low-end 12-bit model is bekend fan in húslik projekt Lightpack. Op ien kear, kieze tusken de DM63x en de bekende TLC5940, keas ik DM foar ferskate redenen: 1) TLC op Aliexpress is perfoarst falsk, mar dizze is net; 2) DM hat in autonome PWM mei in eigen frekwinsjegenerator; 3) it koe goedkeap kocht wurde yn Moskou, ynstee fan te wachtsjen op in pakket fan Ali. En, fansels, it wie ynteressant om te learen hoe't jo de chip sels kontrolearje, ynstee fan in klearmakke bibleteek te brûken. Chips wurde no benammen presintearre yn it SSOP24-pakket; se binne maklik te solderjen oan in adapter.
Sûnt de fabrikant is Taiwaneesk, datasheet de chip is skreaun yn Sineesk Ingelsk, wat betsjut dat it sil wêze leuk. Earst sjogge wy nei de pinout (Pin Ferbining) om te begripen hokker skonk wêrmei te ferbinen is, en in beskriuwing fan 'e pinnen (Pin Beskriuwing). 16 pins:
DC Sink boarnen (iepen drain)
Sinke / Iepen-drain útfier - drain; boarne fan ynstreamende stroom; de útfier is ferbûn mei grûn yn 'e aktive steat - de LED's binne ferbûn mei de bestjoerder troch kathodes. Elektrysk is dit fansels gjin "iepen drain" (iepen drain), mar yn gegevensblêden wurdt dizze oantsjutting foar pinnen yn drainmodus faak fûn.
Eksterne wjerstannen tusken REXT en GND om de hjoeddeistige wearde fan 'e útfier yn te stellen
In referinsje wjerstân wurdt ynstallearre tusken de REXT pin en grûn, dy't kontrolearret de ynterne wjerstân fan de útgongen, sjoch de grafyk op side 9 fan it datasheet. Yn 'e DM634 kin dizze wjerstân ek wurde regele troch software, it ynstellen fan de totale helderheid (globale helderheid); Ik sil yn dit artikel net yngean op details, ik sil hjir gewoan in wjerstân fan 2.2 - 3 kOhm sette.
Om te begripen hoe't jo de chip kontrolearje, litte wy nei de beskriuwing fan 'e apparaatynterface sjen:
Ja, hjir is it, Sineesk Ingelsk yn al syn gloarje. It oersetten fan dit is problematysk, jo kinne it begripe as jo wolle, mar d'r is in oare manier - sjoch hoe't de ferbining mei de funksjoneel ferlykbere TLC5940 wurdt beskreaun yn it datablêd:
... Allinich trije pins binne nedich om gegevens yn it apparaat yn te fieren. De opkommende râne fan it SCLK-sinjaal ferpleatst de gegevens fan 'e SIN-pin nei it ynterne register. Neidat alle gegevens binne laden, in koarte hege XLAT sinjaal latches de sequentially oerdroegen gegevens yn de ynterne registers. Ynterne registers binne poarten trigger troch it XLAT-sinjaalnivo. Alle gegevens wurde oerdroegen meast wichtige bit earst.
Latch - slot / slot / slot. Rising râne - foaroansteande râne fan 'e pols MSB earst - meast wichtige (meast lofts) bytsje foarút. gegevens te klokken - gegevens opfolgjend ferstjoere (bytsje foar bytsje).
It wurd klink wurdt faak fûn yn 'e dokumintaasje foar chips en wurdt oerset op ferskate manieren, dus foar it begryp sil ik mysels tastean
in lyts edukatyf programmaDe LED-bestjoerder is yn wêzen in skiftregister. "Skift" (feroarje) yn 'e namme - bitwize beweging fan gegevens binnen it apparaat: elke nije bit dy't nei binnen skod wurdt, triuwt de hiele ketting foarút. Om't gjinien chaotysk knipperjen fan 'e LED's yn' e skift wol observearje, fynt it proses plak yn bufferregisters skieden fan 'e wurkregisters troch in damper (klink) is in soarte fan wachtkeamer dêr't de bits wurde regele yn de winske folchoarder. As alles klear is, iepenet de sluter en de bits geane oan it wurk, ferfange de foarige batch. Wurd klink Yn de dokumintaasje foar mikrocircuits betsjut hast altyd sa'n damper, nettsjinsteande hokker kombinaasjes it wurdt brûkt.
Dat, gegevensoerdracht nei de DM634 wurdt sa útfierd: set de DAI-ynfier op 'e wearde fan' e meast wichtige bit fan 'e fiere LED, lûk DCK op en del; set de DAI ynfier nei de wearde fan de folgjende bit, pull DCK; en sa fierder oant alle bits binne oerbrocht (ynklokte), wêrnei't wy LAT lûke. Dit kin mei de hân dien wurde (bitsje), mar it is better om in spesjale SPI-ynterface te brûken dy't hjirfoar oanpast is, om't it op ús STM32 yn twa eksimplaren wurdt presintearre.
Blauwe pil STM32F103
Ynliedend: STM32-controllers binne folle komplekser dan Atmega328 dan se miskien lykje eng. Om redenen fan enerzjybesparring wurde hast alle perifeare apparaten by it begjin útskeakele, en de klokfrekwinsje is 8 MHz fan 'e ynterne boarne. Gelokkich skreaunen STM-programmeurs koade dy't de chip bringt nei de "berekkene" 72 MHz, en de auteurs fan alle IDE's dy't ik ken hawwe it opnommen yn 'e inisjalisaasjeproseduere, dus wy hoege net te klokken (mar jo kinne as jo echt wolle). Mar jo moatte de perifeare apparaten ynskeakelje.
Dokumintaasje: Blue Pill is foarsjoen fan de populêre STM32F103C8T6-chip, d'r binne twa nuttige dokuminten foar:
Data Sheet foar mikrocontrollers STM32F103x8 en STM32F103xB;
Yn it datablêd kinne wy ynteressearre wêze yn:
Pinouts - chip pinouts - foar it gefal dat wy beslute om de buorden sels te meitsjen;
Memory Map - ûnthâld map foar in spesifike chip. It Reference Manual hat in kaart foar de hiele line, en it neamt registers dy't ús net hawwe.
Tabel mei pindefinysjes - listje de wichtichste en alternative funksjes fan pins; foar de "blauwe pil" kinne jo handiger foto's fine op it ynternet mei in list mei pinnen en har funksjes. Dêrom googleje wy daliks Blue Pill pinout en hâlde dizze foto by de hân:
NB: der stie in flater yn de foto fan it ynternet, dy’t yn de reaksjes notearre waard, tank dêrfoar. De foto is ferfongen, mar dit is in les - it is better om ynformaasje te kontrolearjen net út gegevensblêden.
Wy ferwiderje it gegevensblêd, iepenje it Reference Manual, en fan no ôf brûke wy allinich it.
Proseduere: wy omgean mei standert ynfier / útfier, konfigurearje SPI, oansette de nedige perifeare apparaten.
Ynput Utfier
Op 'e Atmega328 wurdt I / O ekstreem ienfâldich ymplementearre, en dêrom kin de oerfloed fan STM32-opsjes betiizjend wêze. No hawwe wy allinich konklúzjes nedich, mar sels dizze hawwe fjouwer opsjes:
iepen drain, push-pull, alternative push-pull, alternative iepen drain
"Lûke triuwe" (triuwe-lûke) is de gewoane útfier fan 'e Arduino, de pin kin de wearde HIGH of LOW nimme. Mar mei "iepen drain" binne der swierrichheden, hoewol yn feite alles hjir ienfâldich is:
Utfierkonfiguraasje / as de poarte is tawiisd oan útfier: / útfierbuffer ynskeakele: / - iepen drainmodus: "0" yn it útfierregister stelt N-MOS yn, "1" yn it útfierregister lit de poarte yn Hi-Z-modus ( P-MOS is net aktivearre) / - push-pull modus: "0" yn it útfierregister aktivearret N-MOS, "1" yn it útfierregister aktivearret P-MOS.
Al it ferskil tusken iepen drain (iepen drain) fan "push-pull" (triuwe-lûke) is dat yn 'e earste pin de HIGH-tastân net akseptearje kin: by it skriuwen fan ien nei it útfierregister, giet it yn hege fersetmodus (hege impedânsje, Hoi-Z). By it skriuwen fan nul, gedraacht de pin itselde yn beide modi, sawol logysk as elektrysk.
Yn normale útfiermodus stjoert de pin gewoan de ynhâld fan it útfierregister út. Yn it "alternatyf" wurdt it regele troch de oerienkommende perifeare apparaten (sjoch 9.1.4):
As in haven bit is konfigurearre as in alternative funksje pin, de pin register is útskeakele en de pin is ferbûn mei de perifeare pin.
Alternative funksjonaliteit fan elke pin wurdt beskreaun yn Pin Definysjes It gegevensblêd is op 'e ynladen ôfbylding. Op de fraach wat te dwaan as in pin hat ferskate alternative funksjes, it antwurd wurdt jûn troch in fuotnoat yn it datablêd:
As meardere perifeare apparaten deselde pin brûke, om konflikt tusken alternative funksjes te foarkommen, moat mar ien perifeare apparaat tagelyk brûkt wurde, wikselje mei de perifeare klok ynskeakelje bit (yn it passende RCC-register).
Uteinlik hawwe pins yn útfiermodus ek in kloksnelheid. Dit is in oare enerzjybesparjende funksje; yn ús gefal sette wy it gewoan op maksimaal en ferjitte it.
Dus: wy brûke SPI, wat betsjut dat twa pins (mei gegevens en mei in kloksinjaal) "alternatyf push-pull-funksje" moatte wêze, en in oare (LAT) moat "gewoane push-pull" wêze. Mar foardat se har tawize, litte wy omgean mei SPI.
SPI
In oar lyts edukatyf programma
SPI of Serial Peripheral Interface (seriële perifeare ynterface) is in ienfâldige en tige effektive ynterface foar it ferbinen fan in MK mei oare MK's en de bûtenwrâld yn it algemien. It prinsipe fan syn wurking is al beskreaun hjirboppe, wêr oer de Sineeske LED-bestjoerder (yn de referinsje hantlieding, sjoch paragraaf 25). SPI kin operearje yn master ("master") en slave ("slave") modus. SPI hat fjouwer basiskanalen, wêrfan net allegear kinne wurde brûkt:
MOSI, Master Output / Slave Input: dizze pin stjoert gegevens yn master modus, en ûntfangt gegevens yn slave modus;
MISO, Master Input / Slave Output: krekt oarsom, it ûntfangt yn 'e master, en stjoert yn' e slaaf;
SCK, Serial Clock: stelt de frekwinsje fan gegevens oerdracht yn 'e master of ûntfangt in klok sinjaal yn' e slaaf. Yn essinsje slaan beats;
SS, Slave Selektearje: mei help fan dit kanaal wit de slaaf dat der wat fan him woe. Op STM32 hjit it NSS, dêr't N = negatyf, d.w.s. de controller wurdt in slaaf as der grûn yn dit kanaal. It kombinearret goed mei de Open Drain Output-modus, mar dat is in oar ferhaal.
Lykas al it oare is SPI op STM32 ryk oan funksjonaliteit, dat makket it wat lestich om te begripen. It kin bygelyks net allinich wurkje mei SPI, mar ek mei in I2S-ynterface, en yn 'e dokumintaasje binne har beskriuwingen mingd, it is nedich om it oerskot op 'e tiid ôf te snijen. Us taak is ekstreem ienfâldich: wy moatte gewoan gegevens ferstjoere mei allinich MOSI en SCK. Wy geane nei paragraaf 25.3.4 (heal-duplex kommunikaasje, heal-duplex kommunikaasje), dêr't wy fine 1 klok en 1 unidirectional data wire (1 kloksinjaal en 1 ienrjochtingsdatastream):
Yn dizze modus brûkt de applikaasje SPI yn 'e modus allinich foar ferstjoeren of allinich ûntfangen. / Allinnich útstjoermodus is fergelykber mei dupleksmodus: gegevens wurde oerdroegen op 'e útstjoerpin (MOSI yn mastermodus of MISO yn slavemodus), en de ûntfangstpin (respektyflik MISO of MOSI) kin brûkt wurde as in gewoane I/O-pin . Yn dit gefal hoecht de applikaasje allinich de Rx-buffer te negearjen (as it wurdt lêzen, sil d'r gjin oerdroegen gegevens wêze).
Geweldich, de MISO-pin is fergees, litte wy it LAT-sinjaal dermei ferbine. Litte wy nei Slave Select sjen, dy't op 'e STM32 programmatysk kin wurde regele, wat ekstreem handich is. Wy lêze de paragraaf mei deselde namme yn paragraaf 25.3.1 SPI Algemiene beskriuwing:
Software kontrôle NSS (SSM = 1) / Slave seleksje ynformaasje is befette yn de SSI bit fan de SPI_CR1 register. De eksterne NSS-pin bliuwt fergees foar oare applikaasjebehoeften.
It is tiid om te skriuwen nei de registers. Ik besleat SPI2 te brûken, sykje nei syn basisadres yn it datablêd - yn seksje 3.3 Memory Map:
Iepenje seksje 25.3.3 mei de selsferklearjende titel "SPI konfigurearje yn Master Mode":
1. Stel de serial klok frekwinsje mei bits BR [2: 0] yn de SPI_CR1 register.
De registers wurde sammele yn 'e referinsjehânlieding mei deselde namme. Adres ferskowing (Adres offset) foar CR1 - 0x00, standert wurde alle bits wiske (Weromsette wearde 0x0000):
De BR-bits sette de controller-klokdeler yn, sadat de frekwinsje bepale wêrop de SPI sil operearje. Us STM32-frekwinsje sil 72 MHz wêze, de LED-bestjoerder, neffens syn gegevensblêd, wurket mei in frekwinsje fan maksimaal 25 MHz, dus wy moatte dielen troch fjouwer (BR[2:0] = 001).
2. Stel de CPOL- en CPHA-bits yn om de relaasje tusken gegevensferfier en seriële kloktiming te definiearjen (sjoch diagram op side 240)
Om't wy hjir in gegevensblêd lêze en net nei skema's sjogge, litte wy de tekstbeskriuwing fan 'e CPOL- en CPHA-bits op side 704 (SPI Algemiene beskriuwing) in tichterby besjen:
Klokfaze en polariteit
Mei de CPOL- en CPHA-bits fan it SPI_CR1-register kinne jo programmatysk fjouwer timingrelaasjes selektearje. De CPOL (klokpolariteit) bit kontrolearret de steat fan it kloksinjaal as gjin gegevens wurde oerdroegen. Dit bit kontrolearret de master- en slavemodus. As CPOL wurdt reset, de SCK pin is leech yn rest modus. As de CPOL-bit is ynsteld, is de SCK-pin heech yn 'e rêstmodus.
As de CPHA (klok faze) bit wurdt ynsteld, is de hege bit trap strobe de twadde râne fan de SCK sinjaal (falle as CPOL is dúdlik, opkommende as CPOL is ynsteld). De gegevens wurde fêstlein troch de twadde feroaring yn it kloksinjaal. As de CPHA bit is dúdlik, de hege bit trap strobe is de opkommende râne fan de SCK sinjaal (fallende râne as CPOL is ynsteld, opkommende râne as CPOL wurdt wiske). Gegevens wurde fêstlein by de earste feroaring yn it kloksinjaal.
Nei't dizze kennis opnommen is, komme wy ta de konklúzje dat beide bits nullen moatte bliuwe, om't Wy wolle dat it SCK-sinjaal leech bliuwt as it net yn gebrûk is, en gegevens wurde oerdroegen oan 'e opkommende râne fan' e pols (sjoch Fig. Rising Edge yn it DM634-datablêd).
Trouwens, hjir hawwe wy foar it earst in skaaimerk fan 'e wurdskat yn ST-datasheets tsjinkaam: dêryn is de sin "set it bit nei nul" skreaun in bytsje weromsette, en net in bytsje skjin te meitsjen, lykas bygelyks Atmega.
3. Stel it DFF-bit yn om te bepalen oft it gegevensblok 8-bit of 16-bit formaat is
Ik naam spesifyk in 16-bit DM634 om net te bemuoien mei it ferstjoeren fan 12-bit PWM-gegevens, lykas de DM633. It makket sin om DFF op ien te setten:
4. Konfigurearje it LSBFIRST-bit yn it SPI_CR1-register om it blokformaat te bepalen
LSBFIRST, sa't de namme al fermoeden docht, konfigurearret oerdracht mei it minst signifikante bit earst. Mar DM634 wol ûntfange gegevens begjinnend fan de meast wichtige bit. Dêrom litte wy it weromsette.
5. Yn hardware modus, as ynfier fan de NSS pin is nedich, jilde in hege sinjaal oan de NSS pin tidens de hiele byte oerdracht sequence. Yn NSS software modus, set de SSM en SSI bits yn de SPI_CR1 register. As de NSS-pin moat wurde brûkt as in útfier, moat allinich it SSOE-bit ynsteld wurde.
Ynstallearje SSM en SSI om de NSS-hardwaremodus te ferjitten:
#define SSI 0x0100
#define SSM 0x0200
_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high
6. De MSTR- en SPE-bits moatte ynsteld wurde (se bliuwe allinich ynsteld as it NSS-sinjaal heech is)
Eigentlik, mei dizze bits oanwize wy ús SPI as in master en skeakelje it yn:
SPI is konfigurearre, lit ús fuortendaliks skriuwe funksjes dy't stjoere bytes nei de bestjoerder. Trochgean mei lêzen 25.3.3 "SPI konfigurearje yn mastermodus":
Gegevens oerdracht oarder
Oerdracht begjint as in byte wurdt skreaun nei de Tx buffer.
De gegevensbyte wurdt laden yn it skiftregister by parallel modus (út de ynterne bus) tidens de oerdracht fan de earste bit, wêrnei't it wurdt oerdroegen oan sekwinsjele MOSI pin modus, earste of lêste bit foarút ôfhinklik fan de ynstelling fan de LSBFIRST bit yn de CPI_CR1 register. De TXE flagge wurdt ynsteld nei gegevens oerdracht fan Tx buffer nei ferskowingsregister, en genereart ek in ûnderbrekking as it TXEIE-bit yn it CPI_CR1-register is ynsteld.
Ik markearre in pear wurden yn 'e oersetting om omtinken te jaan oan ien funksje fan' e SPI-ymplemintaasje yn STM-controllers. Op Atmega de TXE flagge (Tx leech, Tx is leech en klear om gegevens te ûntfangen) wurdt pas ynsteld nei't de hiele byte ferstjoerd is út. En hjir dizze flagge wurdt ynsteld neidat de byte is ynfoege yn de ynterne shift register. Sûnt it wurdt skood dêr mei alle bits tagelyk (yn parallel), en dan de gegevens wurdt oerdroegen sequentially, TXE wurdt ynsteld foardat de byte wurdt folslein ferstjoerd. Dit is wichtich omdat yn it gefal fan ús LED-bestjoerder moatte wy de LAT-pin nei it ferstjoeren lûke всех gegevens, d.w.z. De TXE flagge allinnich sil net genôch wêze foar ús.
Dit betsjut dat wy in oare flagge nedich hawwe. Litte wy nei 25.3.7 sjen - "Statusflaggen":
<…>
BUSY flagge
De BSY-flagge wurdt ynsteld en wiske troch hardware (it skriuwen nei it hat gjin effekt). De BSY flagge jout de steat fan de SPI kommunikaasje laach.
It reset:
as de oerdracht foltôge is (útsein yn mastermodus as de oerdracht kontinu is)
wannear SPI is útskeakele
as in mastermodusflater optreedt (MODF=1)
As de oerdracht net kontinu is, wurdt de BSY-flagge wiske tusken elke gegevensoerdracht
Okee, dit komt goed fan pas. Litte wy útfine wêr't de Tx-buffer leit. Om dit te dwaan, lês "SPI Data Register":
Bits 15:0 DR[15:0] Data Register
Gegevens ûntfongen of gegevens dy't oerdroegen wurde.
It gegevensregister is ferdield yn twa buffers - ien foar skriuwen (ferstjoerbuffer) en ien foar lêzen (ûntfangbuffer). Skriuwen nei it gegevensregister skriuwt nei de Tx-buffer, en it lêzen fan it gegevensregister sil de wearde weromjaan yn 'e Rx-buffer.
No, en it statusregister, wêr't de flaggen TXE en BSY binne fûn:
No, om't wy 16 kear twa bytes moatte ferstjoere, neffens it oantal LED-bestjoerderútgongen, sa'n ding:
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();
}
Mar wy witte net hoe te lûken de LAT pin noch, dus wy geane werom nei I / O.
Pins tawize
Yn 'e STM32F1 binne de registers ferantwurdlik foar de steat fan' e pins frij ûngewoan. It is dúdlik dat der mear fan harren as Atmega, mar se binne ek oars as oare STM chips. Seksje 9.1 Algemiene beskriuwing fan GPIO:
Elk fan 'e algemiene doel I / O havens (GPIO) hat twa 32-bit konfiguraasjeregisters (GPIOx_CRL en GPIOx_CRH), twa 32-bit gegevensregisters (GPIOx_IDR en GPIOx_ODR), in 32-bit set-/resetregister (GPIOx_BSRR), in 16-bit resetregister (GPIOx_BRR) en in 32- bit blocking register (GPIOx_LCKR).
De earste twa registers binne ûngewoan, en ek frij ûngemaklik, om't de 16-poarte-pinnen oer har binne ferspraat yn in "fjouwer bits per broer" opmaak. Dy. pins nul oant sân binne yn CRL, en de rest binne yn CRH. Tagelyk befetsje de oerbleaune registers mei súkses de bits fan alle pins fan 'e haven - faak oerbleaun heal "reservearre".
Foar ienfâld, litte wy begjinne fan 'e ein fan' e list.
Wy hawwe gjin blokkearjende register nedich.
De set- en resetregisters binne frij grappich om't se inoar foar in part duplisearje: jo kinne alles allinich skriuwe yn BSRR, wêr't de hegere 16 bits de pin weromsette op nul, en de legere wurde ynsteld op 1, of jo kinne ek brûk BRR, wêrfan de legere 16 bits allinich de pin weromsette. Ik hâld fan 'e twadde opsje. Dizze registers binne wichtich om't se atomêre tagong jouwe ta pinnen:
Atoomset of weromsette
D'r is gjin ferlet om interrupts út te skeakeljen by it programmearjen fan GPIOx_ODR op it bitnivo: ien of mear bits kinne wurde feroare mei in inkele atomêre skriuwoperaasje APB2. Dit wurdt berikt troch it skriuwen fan in "1" nei it set / reset register (GPIOx_BSRR of, foar reset allinne, GPIOx_BRR) fan it bit dat moat wurde feroare. Oare bits sille ûnferoare bliuwe.
De gegevensregisters hawwe frij selsferklearjende nammen - IDR = Ynfier Rjochtingsregister, ynfierregister; ODR = útfier Rjochtingsregister, útfierregister. Wy sille se net nedich wêze yn it hjoeddeistige projekt.
En as lêste, kontrôle registers. Om't wy ynteressearre binne yn 'e twadde SPI-pins, nammentlik PB13, PB14 en PB15, sjogge wy fuortendaliks nei CRH:
En wy sjogge dat wy wat moatte skriuwe yn bits fan 20 oant 31.
Wy hawwe hjirboppe al útfûn wat wy wolle fan pins, dus hjir sil ik sûnder in skermôfbylding dwaan, ik sil gewoan sizze dat MODE de rjochting spesifisearret (ynfier as beide bits binne ynsteld op 0) en pinsnelheid (wy moatte 50MHz, d.w.s. beide pin nei "1"), en CNF stelt de modus: reguliere "push-pull" - 00, "alternatyf" - 10. Standert, sa't wy sjogge hjirboppe, alle pins hawwe de tredde bit fan 'e boaiem (CNF0), it set se yn modus driuwende ynput.
Om't ik fan plan om wat oars te dwaan mei dizze chip, haw ik foar ienfâld alle mooglike MODE- en CNF-wearden definieare foar sawol de legere as boppeste kontrôleregisters.
(LAT_low gewoan troch inertia, it hat altyd sa west, lit it bliuwe)
No is alles geweldich, mar it wurket net. Om't dit STM32 is, besparje se elektrisiteit, wat betsjut dat jo it klokken fan 'e fereaske perifeare apparaten ynskeakelje moatte.
Skeakelje it klokken oan
It horloazje, ek wol bekend as Clock, is ferantwurdlik foar it klokken. En wy koene de ôfkoarting RCC al fernimme. Wy sykje it yn 'e dokumintaasje: dit is Reset en Clock Control.
Lykas hjirboppe sein waard, lokkigernôch, waard it dreechste diel fan it klokûnderwerp foar ús dien troch minsken fan STM, wêrfoar't wy har tige tankje (ik jou nochris in keppeling nei De webside fan Di Halt, om dúdlik te meitsjen hoe betiizjend it is). Wy hawwe allinich registers nedich dy't ferantwurdlik binne foar it ynskeakeljen fan perifeare klokken (Peripheral Clock Enable Registers). Litte wy earst it basisadres fan 'e RCC fine, it is oan it begjin fan' e "Memory Map":
En dan of klikje op de keppeling wêr't jo besykje wat yn 'e plaat te finen, of, folle better, troch de beskriuwingen fan' e aktivearjende registers te gean út 'e seksjes oer ynskeakelje registers. Wêr't wy RCC_APB1ENR en RCC_APB2ENR fine:
En se befetsje dêrtroch bits dy't it klokken fan SPI2, IOPB (I/O-poarte B) en alternative funksjes (AFIO) omfetsje.
As jo de kâns en winsk hawwe om te testen, ferbine dan de DM634 sa: DAI nei PB15, DCK nei PB13, LAT nei PB14. Wy stjoere de bestjoerder fan 5 volt, ferjit net om de grûn te ferbinen.
STM8 PWM
PWM op STM8
Doe't ik dit artikel krekt plande, besleat ik, as foarbyld, om te besykjen om wat funksjonaliteit fan in ûnbekende chip te behearjen mei allinich in gegevensblêd, sadat ik net mei in skuonmakker sûnder laarzen komme soe. STM8 wie ideaal foar dizze rol: as earste hie ik in pear Sineeske boerden mei STM8S103, en twadde, it is net heul populêr, en dêrom is de ferlieding om te lêzen en in oplossing te finen op it ynternet op it ûntbrekken fan dizze oplossingen.
Standert wurket STM8 op in frekwinsje fan 2 MHz, dit moat fuortendaliks korrizjearre wurde.
HSI (High Speed Interne) Klok
It HSI-kloksinjaal is ôflaat fan in ynterne 16 MHz RC-oscillator mei in programmeerbere divider (1 oant 8). It is ynsteld yn de klok divider register (CLK_CKDIVR).
Opmerking: oan it begjin wurdt in HSI RC-oscillator mei in divider fan 8 selektearre as de liedende boarne fan it kloksinjaal.
Wy fine it registeradres yn it datablêd, de beskriuwing yn refman en sjogge dat it register moat wurde wiske:
Om't wy PWM sille útfiere en de LED's ferbine, litte wy nei de pinout sjen:
De chip is lyts, in protte funksjes wurde ophongen op deselde pins. Wat is yn fjouwerkante heakjes is "alternatyf funksjonaliteit", it wurdt oerskeakele troch "opsje bytes" (opsje bytes) - sokssawat as Atmega fuses. Jo kinne har wearden programmatysk feroarje, mar it is net nedich, om't De nije funksjonaliteit wurdt allinich aktivearre nei in herstart. It is makliker te brûken ST Visual Programmer (ynladen mei Visual Develop), dat kin feroarje dizze bytes. De pinout lit sjen dat de CH1 en CH2 pins fan de earste timer binne ferburgen yn fjouwerkante heakjes; it is nedich om de AFR1- en AFR0-bits yn STVP yn te stellen, en de twadde sil ek de CH1-útfier fan 'e twadde timer oerdrage fan PD4 nei PC5.
Sa sille 6 pins de LED's kontrolearje: PC6, PC7 en PC3 foar de earste timer, PC5, PD3 en PA3 foar de twadde.
It ynstellen fan de I/O-pins sels op STM8 is ienfâldiger en logysker dan op STM32:
bekend fan Atmega DDR data rjochtingsregister (Data Rjochting Register): 1 = útfier;
de earste kontrôle register CR1, doe't útfier, stelt de push-pull modus (1) of iepen drain (0); sûnt ik ferbine de LEDs oan de chip mei cathodes, Ik lit nullen hjir;
de twadde kontrôle register CR2, doe't útfier, stelt de klok snelheid: 1 = 10 MHz
PWM Frekwinsje - frekwinsje wêrmei't de timer tikket;
Auto-reload, AR - automatysk laden wearde oant wêr't de timer sil telle (pulsperioade);
Update Event, UEV - in evenemint dat plakfynt as de timer hat teld ta AR;
PWM Duty Cycle - PWM duty cycle, faak neamd "duty factor";
Capture / Ferlykje wearde - wearde foar capture / ferliking, dêr't de timer hat teld sil wat dwaan (yn it gefal fan PWM, it omkeart it útfiersinjaal);
Preload wearde - preloaded wearde. Ferlykje wearde kin net feroarje wylst de timer tikt, oars sil de PWM-syklus brekke. Dêrom wurde nije útstjoerde wearden yn in buffer pleatst en útlutsen as de timer it ein fan syn countdown berikt en weromset wurdt;
Edge-aligned и Midden-ôfstimd modi - ôfstimming lâns de grins en yn it sintrum, itselde as Atmel's Fluch PWM и Fase-korrekte PWM.
OCiREF, Utfier Ferlykje Reference Signal - de referinsje útfier sinjaal, yn feite, wat ferskynt op de oerienkommende pin yn PWM modus.
Lykas al dúdlik is fan 'e pinout, hawwe twa timers PWM-mooglikheden - de earste en de twadde. Beide binne 16-bit, de earste hat in protte ekstra funksjes (benammen it kin sawol omheech en omleech telle). Wy moatte beide gelyk wurkje, dat ik besleat om te begjinnen mei de fansels earmere twadde, om net per ongeluk eat te brûken dat der net is. Guon probleem is dat de beskriuwing fan de PWM funksjonaliteit fan alle timers yn de referinsje hantlieding is yn it haadstik oer de earste timer (17.5.7 PWM Mode), dus jo moatte springe hinne en wer troch it dokumint hiele tiid.
PWM op STM8 hat in wichtich foardiel boppe PWM op Atmega:
Boundary Aligned PWM
Account konfiguraasje fan ûnderen nei boppen
Bottom-up tellen is aktyf as de DIR bit yn it TIM_CR1 register is wiske
Foarbyld:
It foarbyld brûkt de earste PWM-modus. It PWM-referinsjesinjaal OCiREF wurdt heech hâlden sa lang as TIM1_CNT < TIM1_CCRi. Oars nimt it in leech nivo. As de fergelikingswearde yn it TIM1_CCRi-register grutter is dan de autoloadwearde (TIM1_ARR-register), wurdt it OCiREF-sinjaal op 1 hâlden. As de fergelikingswearde 0 is, wurdt OCiREF op nul hâlden....
STM8 timer tidens update evenemint kontrolearret earst ferlykje wearde, en pas dan produsearret in ferwizing sinjaal. Atmega's timer skroeven earst op en fergeliket dan, wat resulteart yn compare value == 0 de útfier is in naald, dy't op ien of oare manier behannele wurde moat (bygelyks troch programmatysk de logika omkeare).
Dus wat wy wolle dwaan: 8-bit PWM (AR == 255), telle fan ûnderen nei boppen, ôfstimming lâns de grins. Sûnt de gloeilampen binne ferbûn mei de chip troch kathodes, de PWM moat útfiere 0 (LED oan) oant ferlykje wearde en 1 nei.
Wy hawwe al lêzen oer guon PWM-modus, dus wy fine it fereaske register fan 'e twadde timer troch te sykjen yn' e referinsje hantlieding foar dizze frase (18.6.8 - TIMx_CCMR1):
110: Earste PWM-modus - by it tellen fan ûnderen nei boppen, is it earste kanaal aktyf wylst TIMx_CNT <TIMx_CCR1. Oars is it earste kanaal ynaktyf. [fierder yn it dokumint is d'r in ferkearde copy-paste fan timer 1] 111: Twadde PWM-modus - by it tellen fan ûnderen nei boppen, is it earste kanaal ynaktyf wylst TIMx_CNT <TIMx_CCR1. Oars is it earste kanaal aktyf.
Sûnt de LED's binne ferbûn mei de MK troch kathodes, past de twadde modus ús (de earste ek, mar wy witte dat noch net).
Bit 3 OC1PE: Ynskeakelje pin 1 preload
0: Preload register op TIMx_CCR1 is útskeakele. Jo kinne op elk momint skriuwe nei TIMx_CCR1. De nije wearde wurket fuortendaliks.
1: Preload register op TIMx_CCR1 is ynskeakele. Lêzen / skriuwe operaasjes tagong ta it foarladen register. De foarladen wearde TIMx_CCR1 wurdt laden yn it skaad register tidens elk update evenemint.
* Opmerking: Foar PWM-modus om goed te wurkjen, moatte de preloadregisters ynskeakele wurde. Dit is net nedich yn ien sinjaal modus (it OPM bit wurdt ynsteld yn de TIMx_CR1 register).
Okee, litte wy alles ynskeakelje wat wy nedich binne foar de trije kanalen fan 'e twadde timer:
De twadde timer kin allinnich telle fan ûnderen nei boppen, ôfstimming lâns de grins, neat moat wurde feroare. Litte wy de frekwinsjeferdieling ynstelle, bygelyks op 256. Foar de twadde timer wurdt de divider ynsteld yn it register TIM2_PSCR en is in krêft fan twa:
Alles wat oerbliuwt is de konklúzjes en de twadde timer sels ynskeakelje. It earste probleem wurdt oplost troch registers Capture / Ferlykje Ynskeakelje: der binne twa, trije kanalen asymmetrysk oer har ferspraat. Hjir kinne wy ek leare dat it mooglik is om de polariteit fan it sinjaal te feroarjen, d.w.s. yn prinsipe wie it mooglik om PWM Mode 1 te brûken. Wy skriuwe:
Litte wy in ienfâldige analoog skriuwe fan AnalogWrite (), dy't de werklike wearden sil oerdrage oan 'e timer foar fergeliking. De registers wurde foarsisber neamd Capture / Ferlykje registers, der binne twa fan harren foar elk kanaal: de lege folchoarder 8 bits yn TIM2_CCRxL en de hege-oarder yn TIM2_CCRxH. Sûnt wy in 8-bit PWM hawwe makke, is it genôch om allinich de minste wichtige bits te skriuwen:
De oandachtige lêzer sil fernimme dat wy in bytsje defekt PWM hawwe, net yn steat om 100% filling te produsearjen (op in maksimale wearde fan 255 wurdt it sinjaal omkeard foar ien timersyklus). Foar LED's makket dit neat út, en de oandachtige lêzer kin al riede hoe't se it reparearje.
PWM op 'e twadde timer wurket, litte wy trochgean nei de earste.
De earste timer hat krekt deselde bits yn deselde registers (it is gewoan dat dy bits dy't bleaunen "reservearre" yn de twadde timer wurde aktyf brûkt yn de earste foar allerhanne avansearre dingen). Dêrom is it genôch om de adressen fan deselde registers yn it datablêd te finen en de koade te kopiearjen. No, feroarje de wearde fan 'e frekwinsjedeler, om't ... de earste timer wol net in krêft fan twa ûntfange, mar in krekte 16-bit wearde yn twa registers Prescaler High и Leech. Wy dogge alles en... de earste timer wurket net. Wat is der oan de hân?
It probleem kin allinnich wurde oplost troch te sjen troch de hiele seksje oer de kontrôle registers fan timer 1, dêr't wy sykje foar de iene dat de twadde timer net hat. Der sil wêze 17.7.30 Breakregister (TIM1_BKR), wêr is dit bytsje:
It tredde mini-projekt is om acht RGB LED's te ferbinen mei de twadde timer yn PWM-modus en meitsje se ferskate kleuren sjen litte. It is basearre op it konsept fan LED-multiplexing, dat is dat as jo LED's heul, heul fluch yn- en útskeakelje, it ús liket dat se konstant oan binne (persistinsje fan fyzje, inertia fan fisuele waarnimming). Ik haw it ienris dien sokssawat op Arduino.
It wurkalgoritme sjocht der sa út:
ferbûn de anode fan de earste RGB LED;
lit it, it stjoeren fan de nedige sinjalen nei de kathodes;
wachte oant it ein fan 'e PWM-syklus;
ferbûn de anode fan de twadde RGB LED;
lit it...
No, ensfh. Fansels, foar prachtige operaasje is it nedich dat de anode is ferbûn en de LED wurdt "ûntstean" tagelyk. No, of hast. Yn alle gefallen moatte wy in koade skriuwe dy't wearden sil útfiere yn trije kanalen fan 'e twadde timer, feroarje se as UEV wurdt berikt, en tagelyk de op it stuit aktive RGB LED feroarje.
Sûnt LED switching is automatysk, wy moatte meitsje in "fideo ûnthâld" út dêr't de interrupt handler sil ûntfange gegevens. Dit is in ienfâldige array:
uint8_t colors[8][3];
Om de kleur fan in spesifike LED te feroarjen, sil it genôch wêze om de fereaske wearden yn dizze array te skriuwen. En de fariabele sil ferantwurdlik wêze foar it oantal aktive LED
uint8_t cnt;
Demux
Foar goede multiplexing, wy moatte, frjemd genôch, in CD74HC238 demultiplexer. Demultiplexer - in chip dy't ymplemintearret de operator yn hardware <<. Troch trije ynfierpinnen (bits 0, 1 en 2) fiede wy it in trije-bit nûmer X, en as antwurd aktivearret it útfiernûmer (1<<X). De oerbleaune yngongen fan 'e chip wurde brûkt om it hiele ûntwerp te skaaljen. Wy hawwe dizze chip net allinich nedich om it oantal besette pins fan 'e mikrocontroller te ferminderjen, mar ek foar feiligens - om net per ongelok mear LED's as mooglik te skeakeljen en de MK net te ferbaarnen. De chip kostet in penny en moat altyd bewarre wurde yn jo medisynkast thús.
Us CD74HC238 sil ferantwurdlik wêze foar it leverjen fan spanning oan 'e anode fan' e winske LED. Yn in folweardige multiplex soe it spanning leverje oan 'e kolom fia in P-MOSFET, mar yn dizze demo is it direkt mooglik, om't it lûkt 20 mA, neffens absolute maksimum wurdearrings yn it datablêd. Fan datasheet CD74HC238 wy hawwe pinouts nedich en dit cheat sheet:
H = heechspanningsnivo, L = leechspanningsnivo, X - net skele
Wy ferbine E2 en E1 oan grûn, E3, A0, A1 en A3 oan pins PD5, PC3, PC4 en PC5 fan STM8. Sûnt de boppesteande tabel befettet sawol lege as hege nivo, wy konfigurearje dizze pins as push-pull pins.
PWM
PWM op 'e twadde timer is op deselde manier konfigureare as yn it foarige ferhaal, mei twa ferskillen:
Earst moatte wy de ûnderbrekking ynskeakelje Update Event (UEV) dy't in funksje sil neame dy't de aktive LED skeakelet. Dit wurdt dien troch it bit te feroarjen Update ûnderbrekking ynskeakelje yn in register mei in sprekkende namme
It twadde ferskil is relatearre oan it ferskynsel fan multiplexing, lykas spoekje - parasitêre gloed fan diodes. Yn ús gefal kin it ferskine fanwege it feit dat de timer, dy't in ûnderbrekking op 'e UEV feroarsake hat, bliuwt te tikjen, en de ûnderbrekkingshanneler hat gjin tiid om de LED te wikseljen foardat de timer begjint wat te skriuwen oan' e pins. Om dit te bestriden, moatte jo de logika omkeare (0 = maksimale helderheid, 255 = neat wurdt ferljochte) en ekstreme duty cycle wearden te foarkommen. Dy. soargje derfoar dat nei UEV de LED's folslein útgeane foar ien PWM-syklus.
Mije it ynstellen fan r, g en b op 255 en tink om se te kearen by it brûken fan se.
Underbrekt
De essinsje fan in ûnderbrekking is dat ûnder bepaalde omstannichheden de chip stopet mei it útfieren fan it haadprogramma en ropt wat eksterne funksje. Underbrekkings komme foar troch eksterne of ynterne ynfloeden, ynklusyf de timer.
Doe't wy earst makke in projekt yn ST Visual Develop, neist main.c wy krigen in rút mei in mysterieuze triem stm8_interrupt_vector.c, automatysk opnommen yn it projekt. Yn dizze triem wurdt in funksje tawiisd oan elke ûnderbrekking NonHandledInterrupt. Wy moatte ús funksje bine oan de winske ûnderbrekking.
It datablêd hat in tabel mei interruptvektoren, wêr't wy dejingen fine dy't wy nedich binne:
Wy moatte feroarje de LED by UEV, dus wy moatte ûnderbrekke # 13.
Dêrom, earst, yn 'e triem stm8_interrupt_vector.c feroarje de standertnamme fan de funksje ferantwurdlik foar ûnderbrekking No.. 13 (IRQ13) nei jo eigen:
{0x82, TIM2_Overflow}, /* irq13 */
As twadde moatte wy in bestân oanmeitsje main.h mei de folgjende ynhâld:
@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;
}
Alles wat oerbliuwt is om ûnderbrekkingen yn te skeakeljen. Dit wurdt dien mei it kommando assembler rim - jo sille it yn sykje moatte Programmearingshanneling:
//enable interrupts
_asm("rim");
In oare assembler kommando is sim - skeakelet ûnderbrekkings út. Se moatte wurde útskeakele wylst nije wearden wurde skreaun nei it "fideoûnthâld", sadat in ûnderbrekking feroarsake op it ferkearde momint de array net bedjerre.
As op syn minst ien dit artikel nuttich fynt, dan haw ik it net om 'e nocht skreaun. Ik sil bliid wêze om opmerkings en opmerkingen te ûntfangen, ik sil besykje alles te beantwurdzjen.