Skaityti 2 duomenų lapus: SPI STM32; PWM, laikmačiai ir pertraukimai STM8
В pirmoji dalis Mėginau pasakyti hobio elektronikos inžinieriams, kurie užaugo iš Arduino kelnių, kaip ir kodėl jie turėtų skaityti duomenų lapus ir kitą mikrovaldiklių dokumentaciją. Tekstas pasirodė didelis, todėl praktinius pavyzdžius pažadėjau parodyti atskirame straipsnyje. Na, jis save vadino pieno grybu...
Šiandien aš jums parodysiu, kaip naudoti duomenų lapus sprendžiant gana paprastas, bet daugeliui projektų, užduočių, reikalingų STM32 („Blue Pill“) ir STM8 valdikliuose. Visi demo projektai yra skirti mano mėgstamiems LED, mes juos apšviesime dideliais kiekiais, tam teks naudoti visokius įdomius periferinius įrenginius.
Tekstas vėlgi pasirodė didžiulis, todėl patogumo dėlei kuriu turinį:
Atsakomybės apribojimas: Nesu inžinierius, neapsimetinėju, kad turiu gilių elektronikos žinių, straipsnis skirtas tokiems mėgėjams kaip aš. Tiesą sakant, prieš dvejus metus save laikiau tiksline auditorija. Jei kas nors man tada būtų pasakęs, kad nepažįstamo lusto duomenų lapus skaityti nebuvo baisu, nebūčiau daug laiko praleidęs ieškodamas kokių nors kodo fragmentų internete ir išradęs ramentus su žirklėmis ir lipnia juostele.
Šiame straipsnyje pagrindinis dėmesys skiriamas duomenų lapams, o ne projektams, todėl kodas gali būti ne itin tvarkingas ir dažnai ankštas. Patys projektai labai paprasti, nors ir tinkami pirmajai pažinčiai su naujuoju lustu.
Tikiuosi, kad mano straipsnis padės kam nors panašiai pasinerti į hobį.
STM32
16 šviesos diodų su DM634 ir SPI
Nedidelis projektas naudojant Blue Pill (STM32F103C8T6) ir DM634 LED tvarkyklę. Naudodami duomenų lapus išsiaiškinsime tvarkyklę, STM IO prievadus ir sukonfigūruosime SPI.
DM634
Taivano lustas su 16 16 bitų PWM išėjimų, gali būti jungiamas grandinėmis. Žemos klasės 12 bitų modelis žinomas iš vietinio projekto Lightpack. Vienu metu, rinkdamasis tarp DM63x ir gerai žinomo TLC5940, pasirinkau DM dėl kelių priežasčių: 1) Aliexpress TLC tikrai yra netikras, bet šis ne; 2) DM turi autonominį PWM su savo dažnio generatoriumi; 3) jį būtų galima nebrangiai nusipirkti Maskvoje, o ne laukti siuntinio iš Ali. Ir, žinoma, buvo įdomu išmokti valdyti lustą patiems, o ne naudoti paruoštą biblioteką. Lustai dabar daugiausia pateikiami SSOP24 pakete, juos lengva lituoti prie adapterio.
Kadangi gamintojas yra taivanietis, duomenų lapas lustas parašytas kinų anglų kalba, vadinasi, bus smagu. Pirmiausia pažiūrime į smeigtuką (Pin Connection) suprasti, prie kurios kojos prie ko prijungti, ir kaiščių aprašymą (Smeigtuko aprašymas). 16 kaiščių:
Nuolatinės srovės kriauklės šaltiniai (atviras kanalizacija)
Kriaukle / Atviro nutekėjimo išėjimas – kanalizacija; įtekančios srovės šaltinis; išėjimas yra prijungtas prie įžeminimo aktyvioje būsenoje - šviesos diodai yra prijungti prie tvarkyklės katodais. Elektriškai tai, žinoma, nėra „atviras nutekėjimas“ (atidaryti kanalizaciją), tačiau duomenų lapuose šis smeigtukų žymėjimas išleidimo režimu dažnai randamas.
Išoriniai rezistoriai tarp REXT ir GND nustatyti išėjimo srovės vertę
Tarp REXT kaiščio ir įžeminimo yra sumontuotas atskaitos rezistorius, kuris valdo išėjimų vidinę varžą, žr. grafiką duomenų lapo 9 puslapyje. DM634 šį pasipriešinimą taip pat galima valdyti programine įranga, nustatant bendrą ryškumą (pasaulinis ryškumas); Šiame straipsnyje nesileisiu į detales, čia tiesiog įdėsiu 2.2–3 kOhm rezistorių.
Norėdami suprasti, kaip valdyti lustą, pažvelkime į įrenginio sąsajos aprašymą:
Taip, čia yra kinų anglų kalba visoje savo šlovėje. Išversti tai yra problematiška, jei norite, galite suprasti, bet yra ir kitas būdas – pažiūrėkite, kaip duomenų lape aprašytas ryšys su funkciškai panašaus TLC5940:
... Norint įvesti duomenis į įrenginį, reikia tik trijų kaiščių. Kylantis SCLK signalo kraštas perkelia duomenis iš SIN kaiščio į vidinį registrą. Įkėlus visus duomenis, trumpas aukštas XLAT signalas užfiksuoja nuosekliai perduodamus duomenis į vidinius registrus. Vidiniai registrai yra vartai, suaktyvinami XLAT signalo lygio. Visi duomenys pirmiausia perduodami reikšmingiausiu bitu.
Latch – skląstis/užraktas/užraktas. Kylantis kraštas – priekinis pulso kraštas MSB pirmiausia – reikšmingiausias (kairysis) bitas į priekį. laikrodžio duomenims – perduoti duomenis nuosekliai (bitas po bito).
Žodis velkė dažnai randamas lustų dokumentacijoje ir yra įvairiai išverstas, todėl supratimo dėlei leisiu sau
nedidelė edukacinė programaLED tvarkyklė iš esmės yra pamainų registras. „Shift“ (perkelti) pavadinime – bitinis duomenų judėjimas įrenginio viduje: kiekvienas naujas įstumtas bitas stumia visą grandinę į priekį priešais save. Kadangi niekas nenori stebėti chaotiško šviesos diodų mirksėjimo pamainos metu, procesas vyksta buferiniuose registruose, atskirtuose nuo darbinių registrų slopintuvu (velkė) yra tam tikras laukimo kambarys, kuriame bitai yra išdėstyti norima seka. Kai viskas bus paruošta, sklendė atsidaro ir antgaliai pradeda dirbti, pakeičiant ankstesnę partiją. Žodis velkė mikroschemų dokumentacijoje beveik visada reiškia tokį slopintuvą, nesvarbu, kokiais deriniais jis naudojamas.
Taigi, duomenų perdavimas į DM634 atliekamas taip: nustatykite DAI įvestį tolimojo šviesos diodo reikšmingiausio bito reikšmę, traukite DCK aukštyn ir žemyn; nustatykite DAI įvestį į kito bito reikšmę, traukite DCK; ir taip toliau, kol visi bitai bus perduoti (įsijungė), po to traukiame LAT. Tai galima padaryti rankiniu būdu (bit-bang), tačiau geriau naudoti specialiai tam pritaikytą SPI sąsają, nes mūsų STM32 ji pateikiama dviem egzemplioriais.
Mėlyna piliulė STM32F103
Įžanga: STM32 valdikliai yra daug sudėtingesni nei Atmega328, nei gali atrodyti baisūs. Be to, energijos taupymo sumetimais beveik visi išoriniai įrenginiai išjungiami, o laikrodžio dažnis yra 8 MHz nuo vidinio šaltinio. Laimei, STM programuotojai parašė kodą, kuris padidina lustą iki "apskaičiuoto" 72 MHz, o visų man žinomų IDE autoriai įtraukė jį į inicijavimo procedūrą, todėl mums nereikia laikrodžio (bet galite, jei tikrai norite). Bet turėsite įjungti periferinius įrenginius.
Dokumentacija: „Blue Pill“ yra su populiariu STM32F103C8T6 lustu, jai yra du naudingi dokumentai:
duomenų lapas mikrovaldikliams STM32F103x8 ir STM32F103xB;
Pinouts – chip pinouts – tuo atveju, jei nuspręstume lentas pasigaminti patys;
Atminties žemėlapis – konkrečios lusto atminties žemėlapis. Nuorodų vadove yra visos linijos žemėlapis ir minimi registrai, kurių mūsų neturi.
Pin Definitions lentelė – išvardijamos pagrindinės ir alternatyvios kaiščių funkcijos; „mėlynajai piliulei“ internete galite rasti patogesnių paveikslėlių su smeigtukų ir jų funkcijų sąrašu. Todėl iškart „Google“ ieškome „Blue Pill pinout“ ir laikome šį paveikslėlį po ranka:
NB: nuotraukoje iš interneto buvo klaida, kuri buvo pažymėta komentaruose, ačiū už tai. Paveikslėlis pakeistas, bet tai pamoka – geriau informaciją tikrinti ne iš duomenų lapų.
Mes pašaliname duomenų lapą, atidarome informacinį vadovą ir nuo šiol naudojame tik jį.
Procedūra: užsiimame standartiniu įėjimu/išėjimu, sukonfigūruojame SPI, įjungiame reikalingus periferinius įrenginius.
Įvesties išvesties
Atmega328 įvestis/išvestis įdiegta itin paprastai, todėl STM32 parinkčių gausa gali suklaidinti. Dabar mums reikia tik išvadų, bet net ir šios turi keturias galimybes:
"Traukti stumti" (stumti traukti) yra įprasta „Arduino“ išvestis, kaiščio reikšmė gali būti HIGH arba LOW. Tačiau su „atviru nutekėjimu“ yra sunkumų, nors iš tikrųjų čia viskas paprasta:
Visas skirtumas tarp atviro kanalizacijos (atidaryti kanalizaciją) iš „stumti-traukti“ (stumti traukti) yra tai, kad pirmame kaištyje negalima priimti HIGH būsenos: įrašant vieną į išvesties registrą, jis pereina į didelio pasipriešinimo režimą (didelės varžos, Sveiki-Z). Rašant nulį, kaištis abiejuose režimuose elgiasi vienodai – tiek logiškai, tiek elektra.
Įprastu išvesties režimu kaištis tiesiog transliuoja išvesties registro turinį. „Alternatyvoje“ jį valdo atitinkami išoriniai įrenginiai (žr. 9.1.4):
Jei prievado bitas sukonfigūruotas kaip alternatyvios funkcijos kaištis, kaiščio registras išjungiamas ir kaištis prijungiamas prie periferinio kaiščio.
Alternatyvios kiekvieno kaiščio funkcijos aprašytos Smeigtukų apibrėžimai Duomenų lapas yra atsisiųstame paveikslėlyje. Į klausimą, ką daryti, jei kaištis turi keletą alternatyvių funkcijų, atsakymas pateikiamas išnašoje duomenų lape:
Jei keli išoriniai įrenginiai naudoja tą patį kaištį, kad būtų išvengta konfliktų tarp alternatyvių funkcijų, vienu metu turėtų būti naudojamas tik vienas periferinis įrenginys, perjungiamas naudojant periferinio laikrodžio įjungimo bitą (atitinkamame RCC registre).
Galiausiai, kaiščiai išvesties režimu taip pat turi laikrodžio greitį. Tai dar viena energijos taupymo funkcija; mūsų atveju mes tiesiog nustatome ją maksimaliai ir pamirštame.
Taigi: mes naudojame SPI, o tai reiškia, kad du kontaktai (su duomenimis ir su laikrodžio signalu) turi būti „alternative push-pull function“, o dar vienas (LAT) turi būti „įprastas stūmimas“. Tačiau prieš priskirdami juos, panagrinėkime SPI.
SPI
Dar viena nedidelė edukacinė programa
SPI arba Serial Peripheral Interface (serijinė periferinė sąsaja) yra paprasta ir labai efektyvi sąsaja, skirta prijungti MK su kitais MK ir išoriniu pasauliu. Jo veikimo principas jau buvo aprašytas aukščiau, kur apie kinišką LED tvarkyklę (žr. 25 skyrių). SPI gali veikti pagrindiniu („master“) ir pavaldiniu („slave“) režimu. SPI turi keturis pagrindinius kanalus, iš kurių ne visi gali būti naudojami:
MOSI, pagrindinė išvestis / pavaldinė įvestis: šis kaištis perduoda duomenis pagrindiniu režimu ir priima duomenis pavaldiniu režimu;
MISO, Master Input / Slave Output: priešingai, priima pagrindiniame įrenginyje, o perduoda vergu;
SCK, Serial Clock: nustato duomenų perdavimo dažnį pagrindiniame įrenginyje arba priima laikrodžio signalą pagalbiniame įrenginyje. Iš esmės pataikyti ritmus;
SS, Slave Select: šio kanalo pagalba vergas žino, kad iš jo kažko norima. STM32 jis vadinamas NSS, kur N = neigiamas, t.y. valdiklis tampa vergu, jei šiame kanale yra įžeminimas. Jis puikiai derinamas su „Open Drain Output“ režimu, bet tai jau kita istorija.
Kaip ir visa kita, SPI STM32 yra daug funkcionalu, todėl jį šiek tiek sunku suprasti. Pavyzdžiui, gali veikti ne tik su SPI, bet ir su I2S sąsaja, o dokumentacijoje jų aprašymai maišomi, reikia laiku nupjauti perteklių. Mūsų užduotis yra labai paprasta: mums tereikia siųsti duomenis naudojant tik MOSI ir SCK. Einame į skyrių 25.3.4 (pusiau dvipusis ryšys, pusiau dvipusis ryšys), kur randame 1 laikrodis ir 1 vienkryptis duomenų laidas (1 laikrodžio signalas ir 1 vienkryptis duomenų srautas):
Šiuo režimu programa naudoja SPI tik perdavimo arba tik priėmimo režimu. / Tik perdavimo režimas yra panašus į dvipusį režimą: duomenys perduodami perdavimo kaiščiu (MOSI pagrindiniu režimu arba MISO pavaldiniu), o priėmimo kaištis (atitinkamai MISO arba MOSI) gali būti naudojamas kaip įprastas įvesties / išvesties kaištis. . Tokiu atveju programai tereikia ignoruoti Rx buferį (jei jis nuskaitomas, ten nebus perkeliami duomenys).
Puiku, MISO kaištis laisvas, prie jo prijungkime LAT signalą. Pažiūrėkime į Slave Select, kurį STM32 galima valdyti programiškai, o tai yra itin patogu. To paties pavadinimo pastraipą skaitome 25.3.1 skirsnyje SPI Bendras aprašymas:
Programinės įrangos valdymo NSS (SSM = 1) / Slave pasirinkimo informacija yra SPI_CR1 registro SSI bite. Išorinis NSS kaištis lieka laisvas kitiems programos poreikiams.
Pats laikas rašyti į registrus. Nusprendžiau naudoti SPI2, jo bazinio adreso ieškokite duomenų lape - 3.3 skyriuje Atminties žemėlapis:
Registrai surinkti to paties pavadinimo žinyno skyriuje. Adreso poslinkis (Adreso poslinkis) CR1 – 0x00, pagal numatytuosius nustatymus visi bitai yra išvalyti (Iš naujo nustatyti vertę 0x0000):
BR bitai nustato valdiklio laikrodžio daliklį, taip nustatydami dažnį, kuriuo veiks SPI. Mūsų STM32 dažnis bus 72 MHz, LED tvarkyklė pagal jos duomenų lapą veikia iki 25 MHz dažniu, todėl reikia dalinti iš keturių (BR[2:0] = 001).
2. Nustatykite CPOL ir CPHA bitus, kad apibrėžtumėte ryšį tarp duomenų perdavimo ir serijinio laikrodžio laiko (žr. diagramą 240 puslapyje).
Kadangi čia skaitome duomenų lapą, o ne žiūrime į schemas, atidžiau pažvelkime į CPOL ir CPHA bitų tekstinį aprašymą 704 puslapyje (SPI bendrasis aprašymas):
Laikrodžio fazė ir poliškumas
Naudodami SPI_CR1 registro CPOL ir CPHA bitus, galite programiškai pasirinkti keturis laiko ryšius. CPOL (laikrodžio poliškumas) bitas kontroliuoja laikrodžio signalo būseną, kai nepersiunčiami jokie duomenys. Šis bitas valdo pagrindinį ir pavaldų režimus. Jei CPOL nustatytas iš naujo, ramybės režimu SCK kaištis yra žemas. Jei CPOL bitas nustatytas, poilsio režimu SCK kaištis yra aukštas.
Kai nustatytas CPHA (laikrodžio fazės) bitas, aukšto bitų gaudyklės stroboskopas yra antrasis SCK signalo kraštas (krenta, jei CPOL yra aiškus, kyla, jei CPOL nustatytas). Duomenys užfiksuojami antrą kartą pasikeitus laikrodžio signalui. Jei CPHA bitas yra aiškus, aukšto bitų gaudyklės blykstė yra kylantis SCK signalo kraštas (krentantis kraštas, jei nustatytas CPOL, kylantis kraštas, jei CPOL išvalytas). Duomenys fiksuojami pirmą kartą pasikeitus laikrodžio signalui.
Įsisavinę šias žinias, darome išvadą, kad abu bitai turi likti nuliai, nes Norime, kad SCK signalas liktų žemas, kai jis nenaudojamas, o duomenys būtų perduodami kylančioje impulso briaunoje (žr. Kylantis kraštas DM634 duomenų lape).
Beje, čia pirmą kartą susidūrėme su ST duomenų lapų žodyno savybe: juose parašyta frazė „atstatyti bitą į nulį“. šiek tiek atstatytiIr ne šiek tiek išvalyti, kaip, pavyzdžiui, Atmega.
3. Nustatykite DFF bitą, kad nustatytumėte, ar duomenų blokas yra 8 bitų ar 16 bitų formato
Aš specialiai paėmiau 16 bitų DM634, kad nesivarginčiau perduodant 12 bitų PWM duomenis, pavyzdžiui, DM633. Tikslinga nustatyti DFF į vieną:
4. Sukonfigūruokite LSBFIRST bitą SPI_CR1 registre, kad nustatytumėte bloko formatą
LSBFIRST, kaip rodo jo pavadinimas, pirmiausia sukonfigūruoja perdavimą su mažiausiai reikšmingu bitu. Tačiau DM634 nori gauti duomenis pradedant nuo svarbiausio bito. Todėl paliekame jį nustatyti iš naujo.
5. Aparatūros režimu, jei reikalinga įvestis iš NSS kaiščio, per visą baitų perdavimo seką NSS kaiščiui pritaikykite aukštą signalą. NSS programinės įrangos režimu nustatykite SSM ir SSI bitus SPI_CR1 registre. Jei NSS kaištis turi būti naudojamas kaip išėjimas, reikia nustatyti tik SSOE bitą.
Įdiekite SSM ir SSI, kad pamirštumėte apie NSS aparatinės įrangos režimą:
#define SSI 0x0100
#define SSM 0x0200
_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high
6. Turi būti nustatyti MSTR ir SPE bitai (jie lieka nustatyti tik tada, kai NSS signalas yra aukštas)
Tiesą sakant, naudodami šiuos bitus mes priskiriame savo SPI kaip pagrindinį ir įjungiame:
SPI sukonfigūruotas, iš karto rašykime funkcijas, kurios siunčia baitus vairuotojui. Skaitykite toliau 25.3.3 „SPI konfigūravimas pagrindiniame režime“:
Duomenų perdavimo užsakymas
Perdavimas prasideda, kai baitas įrašomas į Tx buferį.
Duomenų baitas įkeliamas į pamainų registrą lygiagrečiai režimu (iš vidinės magistralės) perduodant pirmąjį bitą, po kurio jis perduodamas į nuosekliai MOSI kaiščio režimas, pirmasis arba paskutinis bitas į priekį, priklausomai nuo LSBFIRST bito nustatymo CPI_CR1 registre. TXE vėliavėlė nustatoma po duomenų perdavimo iš Tx buferio į pamainų registrą, taip pat generuoja pertraukimą, jei CPI_CR1 registre nustatytas TXEIE bitas.
Vertime paryškinau keletą žodžių, kad atkreipčiau dėmesį į vieną SPI diegimo STM valdikliuose ypatybę. Ant Atmega TXE vėliava (Tx tuščias, Tx tuščias ir paruoštas priimti duomenis) nustatomas tik tada, kai buvo išsiųstas visas baitas išėjo. Ir čia ši vėliavėlė nustatoma po to, kai baitas buvo įterptas į vidinį poslinkių registrą. Kadangi jis yra stumiamas ten su visais bitais vienu metu (lygiagrečiai), o tada duomenys perduodami nuosekliai, TXE nustatomas prieš baitą iki galo. Tai svarbu, nes mūsų LED tvarkyklės atveju po siuntimo turime ištraukti LAT kaištį visi duomenis, t.y. Vien TXE vėliavėlės mums neužteks.
Tai reiškia, kad mums reikia kitos vėliavos. Pažvelkime į 25.3.7 – „Būsenos vėliavėlės“:
<…>
UŽIMTA vėliava
BSY vėliavėlę nustato ir išvalo aparatinė įranga (įrašymas į ją neturi jokio poveikio). BSY vėliavėlė nurodo SPI ryšio sluoksnio būseną.
Iš naujo nustatoma:
kai perkėlimas baigtas (išskyrus pagrindinį režimą, jei perdavimas yra tęstinis)
kai SPI išjungtas
kai įvyksta pagrindinio režimo klaida (MODF=1)
Jei perdavimas nėra tęstinis, BSY vėliavėlė išvaloma tarp kiekvieno duomenų perdavimo
Gerai, tai pravers. Išsiaiškinkime, kur yra Tx buferis. Norėdami tai padaryti, skaitykite „SPI duomenų registras“:
Bitai 15:0 DR[15:0] Duomenų registras
Gauti arba perduotini duomenys.
Duomenų registras yra padalintas į du buferius – vieną rašymui (perdavimo buferis) ir kitą skaitymui (gavimo buferis). Įrašant į duomenų registrą įrašoma į Tx buferį, o nuskaitant iš duomenų registro bus grąžinta reikšmė, esanti Rx buferyje.
Na, ir būsenos registras, kuriame yra TXE ir BSY vėliavėlės:
Na, kadangi mums reikia perduoti 16 kartų du baitus, atsižvelgiant į LED tvarkyklės išėjimų skaičių, maždaug taip:
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();
}
Tačiau dar nežinome, kaip ištraukti LAT kaištį, todėl grįšime į I/O.
Smeigtukų priskyrimas
STM32F1 registrai, atsakingi už kaiščių būklę, yra gana neįprasti. Aišku, kad jų yra daugiau nei „Atmega“, tačiau jie skiriasi ir nuo kitų STM lustų. 9.1 skirsnis Bendrasis GPIO aprašas:
Kiekvienas bendrosios paskirties I/O prievadas (GPIO) turi du 32 bitų konfigūracijos registrus (GPIOx_CRL ir GPIOx_CRH), du 32 bitų duomenų registrus (GPIOx_IDR ir GPIOx_ODR), 32 bitų nustatymo/atstatymo registrą (GPIOx_BSRR), 16 bitų nustatymo iš naujo registrą (GPIOx_BRR) ir 32 bitų registrą. bitų blokavimo registras (GPIOx_LCKR).
Pirmieji du registrai yra neįprasti, o taip pat gana nepatogūs, nes 16 prievadų kontaktų yra išsklaidyti juose „keturi bitai vienam broliui“ formatu. Tie. kaiščiai nuo nulio iki septynių yra CRL, o kiti yra CRH. Tuo pačiu metu likusiuose registruose sėkmingai yra visų prievado kaiščių bitai - dažnai lieka pusiau „rezervuoti“.
Kad būtų paprasčiau, pradėkime nuo sąrašo pabaigos.
Mums nereikia blokavimo registro.
Nustatyti ir atstatyti registrai gan juokingi tuo, kad dalinai dubliuoja vienas kitą: rašyti viską galima tik BSRR, kur didesni 16 bitų atstatys piną į nulį, o žemesni – į 1 arba galima ir naudokite BRR, kurio apatiniai 16 bitų atstato tik kaištį . Man patinka antras variantas. Šie registrai yra svarbūs, nes suteikia atominę prieigą prie kaiščių:
Atominis nustatymas arba nustatymas iš naujo
Programuojant GPIOx_ODR bitų lygiu pertraukimų išjungti nereikia: vieną ar daugiau bitų galima pakeisti viena atominio rašymo operacija APB2. Tai pasiekiama įrašant „1“ į nustatymo/atstatymo registrą (GPIOx_BSRR arba, tik atstatymui, GPIOx_BRR), kurį reikia pakeisti. Kiti bitai išliks nepakitę.
Duomenų registrai turi gana savaime suprantamus pavadinimus – IDR = Indėlis Krypties registras, įvesties registras; ODR = produkcija Krypties registras, išvesties registras. Dabartiniame projekte jų mums nereikės.
Ir galiausiai, valdymo registrai. Kadangi mus domina antrieji SPI kaiščiai, būtent PB13, PB14 ir PB15, iš karto žiūrime į CRH:
Ir matome, kad reikės ką nors parašyti bitais nuo 20 iki 31.
Aukščiau jau išsiaiškinome, ko norime iš kaiščių, todėl čia apsieisiu be ekrano kopijos, tik pasakysiu, kad MODE nurodo kryptį (įvestis, jei abu bitai nustatyti į 0) ir kaiščio greitį (mums reikia 50MHz, t.y. abu kaiščiai yra „1“), o CNF nustato režimą: įprastas „push-pull“ – 00, „alternatyvus“ – 10. Pagal numatytuosius nustatymus, kaip matome aukščiau, visi kaiščiai turi trečiąjį bitą iš apačios (CNF0), tai nustato juos į režimą slankioji įvestis.
Kadangi su šiuo lustu planuoju daryti ką nors kita, dėl paprastumo apibrėžiau visas galimas MODE ir CNF reikšmes tiek apatiniame, tiek viršutiniame valdymo registruose.
(LAT_žemas tik iš inercijos, visada taip buvo, tegul lieka)
Dabar viskas puiku, bet neveikia. Kadangi tai yra STM32, jie taupo elektros energiją, o tai reiškia, kad reikia įjungti reikalingų išorinių įrenginių laikrodį.
Įjunkite laikrodį
Laikrodis, taip pat žinomas kaip laikrodis, yra atsakingas už laikrodžio rodymą. Ir jau galėjome pastebėti santrumpą RCC. Mes jo ieškome dokumentacijoje: tai yra Reset ir Clock Control.
Kaip buvo sakyta aukščiau, laimei, sunkiausią laiko temos dalį mums atliko STM žmonės, už ką jiems labai dėkojame (dar kartą pateiksiu nuorodą į Di Halto svetainė, kad būtų aišku, kaip tai painu). Mums reikia tik registrų, atsakingų už periferinio laikrodžio įjungimą (Peripheral Clock Enable Registers). Pirmiausia suraskime bazinį RCC adresą, jis yra pačioje „Atminties žemėlapio“ pradžioje:
Tada arba spustelėkite nuorodą, kurioje bandote ką nors rasti plokštelėje, arba, daug geriau, peržiūrėkite įgalinančių registrų aprašymus iš skyrių apie įjungti registrus. Kur rasime RCC_APB1ENR ir RCC_APB2ENR:
Atitinkamai juose yra bitų, apimančių SPI2, IOPB (I/O prievadas B) ir alternatyvias funkcijas (AFIO).
Jei turite galimybę ir noro išbandyti, tuomet DM634 prijunkite taip: DAI prie PB15, DCK prie PB13, LAT prie PB14. Vairuotoją maitiname nuo 5 voltų, nepamirškite prijungti įžeminimo.
STM8 PWM
PWM STM8
Kai tik planavau šį straipsnį, nusprendžiau, kaip pavyzdį, pabandyti įvaldyti nepažįstamo lusto funkcionalumą naudojant tik duomenų lapą, kad neliktų batsiuvys be batų. STM8 puikiai tiko šiam vaidmeniui: pirma, turėjau porą kiniškų plokščių su STM8S103, antra, ji nėra labai populiari, todėl pagunda skaityti ir rasti sprendimą internete remiasi būtent šių sprendimų stoka.
Pagal numatytuosius nustatymus STM8 veikia 2 MHz dažniu, tai reikia nedelsiant ištaisyti.
HSI (didelio greičio vidinis) laikrodis
HSI laikrodžio signalas gaunamas iš vidinio 16 MHz RC osciliatoriaus su programuojamu dalikliu (nuo 1 iki 8). Jis nustatomas laikrodžio skirstytuvo registre (CLK_CKDIVR).
Pastaba: pradžioje HSI RC generatorius su dalikliu 8 pasirenkamas kaip pagrindinis laikrodžio signalo šaltinis.
Duomenų lape randame registro adresą, refman aprašą ir matome, kad registrą reikia išvalyti:
Kadangi ketiname paleisti PWM ir prijungti šviesos diodus, pažiūrėkime į kištuką:
Lustas yra mažas, daugelis funkcijų yra pakabintos ant tų pačių kaiščių. Tai, kas yra laužtiniuose skliaustuose, yra „alternatyvi funkcija“, ji perjungiama „parinkčių baitais“ (parinkčių baitų) – kažkas panašaus į Atmega saugiklius. Galite keisti jų reikšmes programiškai, bet tai nėra būtina, nes Nauja funkcija aktyvuojama tik paleidus iš naujo. Lengviau naudoti ST Visual Programer (atsisiųstas su Visual Develop), kuris gali pakeisti šiuos baitus. Smeigtukas rodo, kad pirmojo laikmačio CH1 ir CH2 kaiščiai yra paslėpti laužtiniuose skliaustuose; reikia nustatyti AFR1 ir AFR0 bitus STVP, o antrasis taip pat perkels antrojo laikmačio CH1 išvestį iš PD4 į PC5.
Taigi, 6 kontaktai valdys šviesos diodus: PC6, PC7 ir PC3 pirmajam laikmačiui, PC5, PD3 ir PA3 antrajam.
Pačių įvesties / išvesties kaiščių nustatymas STM8 yra paprastesnis ir logiškesnis nei STM32:
pažįstamas iš Atmega DDR duomenų krypčių registro (Duomenų krypties registras): 1 = išvestis;
pirmasis valdymo registras CR1, kai išvedamas, nustato „push-pull“ režimą (1) arba atvirą nutekėjimą (0); kadangi šviesos diodus prie lusto jungiu katodais, tai čia palieku nulius;
antrasis valdymo registras CR2, kai išvedamas, nustato taktinį dažnį: 1 = 10 MHz
Automatinis įkėlimas iš naujo, AR – automatiškai įkeliama vertė, iki kurios laikmatis skaičiuos (impulso periodas);
Atnaujinti įvykį, UEV – įvykis, įvykęs, kai laikmatis skaičiuoja iki AR;
PWM darbo ciklas – PWM darbo ciklas, dažnai vadinamas „darbo koeficientu“;
Užfiksuokite / palyginkite vertę – fiksavimo / palyginimo vertė, į kurią atsiskaito laikmatis ką nors padarys (PWM atveju jis apverčia išvesties signalą);
Išankstinės įkrovos vertė – iš anksto įkelta vertė. Palyginkite vertę negali pasikeisti, kol tiksi laikmatis, kitaip PWM ciklas nutrūks. Todėl naujos perduodamos reikšmės dedamos į buferį ir ištraukiamos, kai laikmatis pasiekia atgalinės atskaitos pabaigą ir nustatomas iš naujo;
Išlygintas kraštais и Išlygiuoti centre režimai – lygiavimas išilgai sienos ir centre, toks pat kaip Atmel Greitas PWM и Fazės teisingas PWM.
OCiREF, išvesties palyginimo atskaitos signalas – atskaitos išvesties signalas, iš tikrųjų tai, kas rodoma atitinkamame kaištyje PWM režimu.
Kaip jau aišku iš pinout, du laikmačiai turi PWM galimybes – pirmasis ir antrasis. Abu yra 16 bitų, pirmasis turi daug papildomų funkcijų (ypač, jis gali skaičiuoti ir aukštyn, ir žemyn). Reikia, kad abu dirbtų vienodai, todėl nusprendžiau pradėti nuo akivaizdžiai prastesnio antrojo, kad netyčia nepanaudotų kažko, ko nėra. Tam tikra problema yra ta, kad visų laikmačių PWM funkcionalumo aprašymas informaciniame vadove yra skyriuje apie pirmąjį laikmatį (17.5.7 PWM režimas), todėl visą laiką turite šokinėti pirmyn ir atgal visame dokumente.
PWM STM8 turi svarbų pranašumą prieš PWM Atmega:
Ribų suderintas PWM
Paskyros konfigūracija iš apačios į viršų
Skaičiavimas iš apačios į viršų yra aktyvus, jei išvalytas DIR bitas TIM_CR1 registre
Pavyzdys
Pavyzdyje naudojamas pirmasis PWM režimas. PWM atskaitos signalas OCiREF laikomas aukštai tol, kol TIM1_CNT < TIM1_CCRI. Priešingu atveju reikia žemo lygio. Jei palyginimo vertė TIM1_CCRI registre yra didesnė už automatinio įkėlimo vertę (TIM1_ARR registras), OCiREF signalas laikomas 1. Jei palyginamoji vertė yra 0, OCiREF laikomas nuliu....
STM8 laikmatis metu atnaujinimo įvykis pirmiausia patikrina palyginti vertę, ir tik tada sukuria atskaitos signalą. „Atmega“ laikmatis pirmiausia įsijungia, o tada palygina, todėl gaunama compare value == 0 išvestis yra adata, su kuria reikia kažkaip susitvarkyti (pavyzdžiui, programiškai apverčiant logiką).
Taigi, ką mes norime padaryti: 8 bitų PWM (AR == 255), skaičiuojant iš apačios į viršų, išlygiavimas išilgai sienos. Kadangi lemputės prie lusto sujungtos katodais, PWM turėtų išvesti 0 (įsijungs šviesos diodas), kol palyginti vertę ir 1 po.
Apie kai kuriuos jau skaitėme PWM režimas, todėl reikiamą antrojo laikmačio registrą randame ieškodami informaciniame vadove šios frazės (18.6.8 – TIMx_CCMR1):
110: Pirmasis PWM režimas – skaičiuojant iš apačios į viršų, pirmasis kanalas yra aktyvus, kai TIMx_CNT < TIMx_CCR1. Kitu atveju pirmasis kanalas bus neaktyvus. [toliau dokumente yra klaidingas kopijavimas-įklijavimas iš 1 laikmačio] 111: Antrasis PWM režimas – skaičiuojant iš apačios į viršų, pirmasis kanalas yra neaktyvus, o TIMx_CNT < TIMx_CCR1. Priešingu atveju pirmasis kanalas bus aktyvus.
Kadangi šviesos diodai su MK sujungti katodais, mums tinka antrasis režimas (pirmasis irgi, bet to dar nežinome).
3 bitas OC1PE: įgalinkite 1 kaiščio išankstinį įkėlimą
0: TIMx_CCR1 išankstinio įkėlimo registras išjungtas. Į TIMx_CCR1 galite rašyti bet kuriuo metu. Nauja vertė veikia iš karto.
1: TIMx_CCR1 išankstinio įkėlimo registras įjungtas. Skaitymo / rašymo operacijos pasiekia išankstinio įkėlimo registrą. Iš anksto įkelta vertė TIMx_CCR1 įkeliama į šešėlių registrą kiekvieno atnaujinimo įvykio metu.
*Pastaba: kad PWM režimas veiktų tinkamai, turi būti įjungti išankstinio įkėlimo registrai. Tai nėra būtina vieno signalo režimu (OPM bitas nustatytas TIMx_CR1 registre).
Gerai, įjunkime viską, ko reikia trims antrojo laikmačio kanalams:
Antrasis laikmatis gali skaičiuoti tik iš apačios į viršų, lygiavimas palei sieną, nieko keisti nereikia. Pavyzdžiui, nustatykime dažnio daliklį į 256. Antrojo laikmačio daliklis nustatomas TIM2_PSCR registre ir yra dviejų laipsnis:
Belieka įjungti išvadas ir patį antrąjį laikmatį. Pirmąją problemą išsprendžia registrai Užfiksuoti/palyginti Įjungti: juose asimetriškai išsibarstę du, trys kanalai. Čia taip pat galime sužinoti, kad galima keisti signalo poliškumą, t.y. iš esmės buvo galima naudoti PWM režimą 1. Rašome:
Parašykime paprastą AnalogWrite() analogą, kuris palyginimui perduos faktines reikšmes į laikmatį. Registrai pavadinti nuspėjamai Užfiksuokite / palyginkite registrus, kiekvienam kanalui yra du iš jų: žemos eilės 8 bitai TIM2_CCRxL ir aukščiausios eilės TIM2_CCRxH. Kadangi sukūrėme 8 bitų PWM, pakanka parašyti tik mažiausiai reikšmingus bitus:
Dėmesingas skaitytojas pastebės, kad turime šiek tiek sugedusį PWM, negalintį pagaminti 100% užpildymo (esant maksimaliai 255 vertei, signalas apverčiamas vienam laikmačio ciklui). Šviesos diodams tai nesvarbu, o dėmesingas skaitytojas jau gali atspėti, kaip tai ištaisyti.
PWM ant antrojo laikmačio veikia, pereikime prie pirmojo.
Pirmasis laikmatis turi lygiai tuos pačius bitus tuose pačiuose registruose (tiesiog tie bitai, kurie liko „rezervuoti“ antrajame laikmatyje, pirmajame aktyviai naudojami įvairiems pažangiems dalykams). Todėl pakanka duomenų lape surasti tų pačių registrų adresus ir nukopijuoti kodą. Na, pakeiskite dažnio daliklio reikšmę, nes... pirmasis laikmatis nori gauti ne dviejų laipsnį, o tikslią 16 bitų reikšmę dviejuose registruose Prescaler High и žemas. Viską darome ir... neveikia pirmas laikmatis. Kas nutiko?
Problemą galima išspręsti tik peržvelgus visą skyrių apie 1 laikmačio valdymo registrus, kur ieškome to, kurio antrasis laikmatis neturi. Bus 17.7.30 Pertraukų registras (TIM1_BKR), kur yra ši dalis:
Trečiasis mini projektas yra prijungti aštuonis RGB šviesos diodus prie antrojo laikmačio PWM režimu ir priversti juos rodyti skirtingas spalvas. Jis pagrįstas LED multipleksavimo koncepcija, ty jei labai labai greitai įjungsite ir išjungsite šviesos diodus, mums atrodys, kad jie nuolat dega (regėjimo išlikimas, vizualinio suvokimo inercija). kažkada padariau kažkas panašaus į Arduino.
Darbo algoritmas atrodo taip:
prijungtas pirmojo RGB šviesos diodo anodas;
jį uždegė, siųsdamas reikiamus signalus į katodus;
laukė iki PWM ciklo pabaigos;
prijungė anodą RGB LED anodą;
uždegė...
Na ir t.t. Žinoma, norint gražiai veikti, reikia, kad tuo pačiu metu būtų prijungtas anodas ir „uždegamas“ šviesos diodas. Na, arba beveik. Bet kokiu atveju turime parašyti kodą, kuris išves reikšmes trijuose antrojo laikmačio kanaluose, pakeis jas pasiekus UEV ir tuo pačiu pakeis šiuo metu aktyvų RGB šviesos diodą.
Kadangi šviesos diodų perjungimas yra automatinis, turime sukurti „vaizdo atmintį“, iš kurios pertraukimų tvarkytojas gaus duomenis. Tai paprastas masyvas:
uint8_t colors[8][3];
Norint pakeisti konkretaus šviesos diodo spalvą, pakaks į šį masyvą įrašyti reikiamas reikšmes. O kintamasis bus atsakingas už aktyvaus šviesos diodo skaičių
uint8_t cnt;
Demux
Norint tinkamai sutankinti, mums, kaip bebūtų keista, reikia CD74HC238 demultiplekserio. Demultiplekseris – lustas, įgyvendinantis operatorių aparatinėje įrangoje <<. Per tris įvesties kaiščius (bitai 0, 1 ir 2) mes jam tiekiame trijų bitų skaičių X, o atsakydamas jis suaktyvina išvesties numerį (1<<X). Likusios lusto įvestys naudojamos viso dizaino masteliui padidinti. Šis lustas reikalingas ne tik tam, kad sumažintume užimtų mikrovaldiklio kontaktų skaičių, bet ir dėl saugumo – kad netyčia neįsijungtume daugiau šviesos diodų nei įmanoma ir nesudegintume MK. Lustas kainuoja centą ir visada turėtų būti laikomas savo namų vaistinėlėje.
Mūsų CD74HC238 bus atsakingas už įtampos tiekimą į norimo LED anodo. Visavertiame multiplekse jis tiektų įtampą į kolonėlę per P-MOSFET, tačiau šioje demonstracijoje tai įmanoma tiesiogiai, nes jis naudoja 20 mA, pagal Absoliučiai maksimalus įvertinimas duomenų lape. Nuo duomenų lapas CD74HC238 mums reikia pinouts ir šio cheat sheet:
H = aukštos įtampos lygis, L = žemos įtampos lygis, X – nerūpi
E2 ir E1 jungiame prie įžeminimo, E3, A0, A1 ir A3 prie STM5 kaiščių PD3, PC4, PC5 ir PC8. Kadangi aukščiau pateiktoje lentelėje yra ir žemų, ir aukštų lygių, šiuos kaiščius sukonfigūruojame kaip stumiamus kaiščius.
PWM
Antrojo laikmačio PWM sukonfigūruotas taip pat, kaip ir ankstesnėje istorijoje, su dviem skirtumais:
Pirmiausia turime įjungti pertraukimą Atnaujinti įvykį (UEV), kuri iškvies funkciją, kuri perjungia aktyvų šviesos diodą. Tai daroma keičiant bitą Atnaujinimo pertraukimo įgalinimas registre su iškalbingu vardu
Antrasis skirtumas yra susijęs su tankinimo reiškiniu, pvz šešėlius – parazitinis diodų švytėjimas. Mūsų atveju tai gali pasirodyti dėl to, kad laikmatis, sukėlęs UEV pertraukimą, ir toliau tiksi, o pertraukų tvarkytojas nespėja perjungti šviesos diodo, kol laikmatis pradeda kažką rašyti į kaiščius. Norėdami su tuo kovoti, turėsite pakeisti logiką (0 = didžiausias ryškumas, 255 = niekas nedega) ir vengti ekstremalių darbo ciklo verčių. Tie. įsitikinkite, kad po UEV šviesos diodai visiškai užgęsta vienam PWM ciklui.
Venkite r, g ir b nustatyti iki 255 ir nepamirškite jų apversti, kai naudojate juos.
Pertraukia
Pertraukimo esmė yra ta, kad tam tikromis aplinkybėmis lustas nustoja vykdyti pagrindinę programą ir iškviečia kokią nors išorinę funkciją. Pertraukimai atsiranda dėl išorinių ar vidinių poveikių, įskaitant laikmatį.
Kai pirmą kartą sukūrėme projektą „ST Visual Develop“, be to main.c gavome langą su paslaptinga byla stm8_interrupt_vector.c, automatiškai įtrauktas į projektą. Šiame faile kiekvienai pertraukimui priskiriama funkcija NonHandledInterrupt. Turime susieti savo funkciją su norimu pertraukimu.
Duomenų lape yra pertraukimo vektorių lentelė, kurioje randame mums reikalingus:
@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;
}
Belieka tik įjungti pertraukimus. Tai atliekama naudojant komandą assembler rim – teks jos ieškoti Programavimo vadovas:
//enable interrupts
_asm("rim");
Kita surinkėjo komanda yra sim – išjungia pertraukimus. Jie turi būti išjungti, kol į „vaizdo atmintį“ įrašomos naujos reikšmės, kad netinkamu momentu įvykęs pertraukimas nesugadintų masyvo.