Llegiu els fulls de dades 2: SPI a STM32; PWM, temporitzadors i interrupcions a STM8
В la primera part Vaig intentar dir als enginyers electrònics aficionats que van sorgir dels pantalons Arduino com i per què haurien de llegir fulls de dades i altra documentació per als microcontroladors. El text va resultar ser gran, així que em vaig comprometre a mostrar exemples pràctics en un article separat. Bé, es deia carregador...
Avui us mostraré com utilitzar fulls de dades per resoldre tasques bastant senzilles, però necessàries per a molts projectes amb controladors STM32 (Blue Pill) i STM8. Tots els projectes de demostració estan dedicats als meus LED preferits, els il·luminarem en grans quantitats, per a això haurem d'utilitzar tot tipus de perifèrics interessants.
El text va tornar a resultar enorme, així que per comoditat estic fent el contingut:
Exempció de responsabilitat: no sóc enginyer, no pretenc tenir coneixements profunds en electrònica, l'article està pensat per a aficionats com jo. De fet, fa dos anys em vaig considerar com el públic objectiu. Si algú m'hagués dit aleshores que no fa por llegir fulls de dades d'un xip desconegut, no hauria passat gaire temps buscant alguns fragments de codi a Internet i inventant crosses amb tisores i guix adhesiu.
L'objectiu d'aquest article són les fitxes de dades, no els esborranys, de manera que el codi pot no estar massa polit i sovint una crossa. Els projectes en si són molt senzills, tot i que són adequats per al primer coneixement d'un xip nou.
Espero que el meu article ajudi algú en una etapa similar de submergir-se en un hobby.
STM32
16 LED amb DM634 i SPI
Petit projecte amb Blue Pill (STM32F103C8T6) i controlador LED DM634. Amb l'ajuda de fulls de dades, tractarem el controlador, els ports STM IO i configurarem SPI.
DM634
Xip taiwanès amb sortides PWM de 16 x 16 bits, es pot encadenar. El model més jove de 12 bits es coneix per un projecte domèstic paquet de llum. En un moment, escollint entre DM63x i el conegut TLC5940, em vaig optar per DM per diversos motius: 1) TLC a Aliexpress és definitivament fals, però aquest no ho és; 2) DM té un PWM autònom amb el seu propi generador de freqüència; 3) es podria comprar a bon preu a Moscou i no esperar un paquet d'Ali. I, per descomptat, va ser interessant aprendre a controlar el xip tu mateix i no utilitzar una biblioteca ja feta. Els xips ara es presenten principalment al paquet SSOP24, són fàcils de soldar a l'adaptador.
Com que el fabricant és taiwanès, fitxa de dades to the xip està escrit en xinès anglès, el que significa que serà divertit. Primer mira el pinoutConnexió de pins) per entendre quina pota connectar què i una descripció dels pins (Descripció del pin). 16 pins:
Enfonsa fonts de corrent continu (desguàs obert)
Fregadero / Sortida de drenatge obert - estoc; font de corrent entrant; una sortida connectada a terra en estat actiu: els LED estan connectats al controlador mitjançant càtodes. Elèctricament, això no és, per descomptat, un "desguàs obert" (desguàs obert), però a les fitxes de dades es troba sovint una designació d'aquest tipus per a sortides en mode drenatge.
Resistències externes entre REXT i GND per establir el valor del corrent de sortida
S'instal·la una resistència de referència entre el pin REXT i la terra, que controla la resistència interna de les sortides, vegeu el gràfic de la pàgina 9 del full de dades. Al DM634, aquesta resistència també es pot controlar mitjançant programari configurant la brillantor general (brillantor global); No entraré en detalls en aquest article, només posaré aquí una resistència de 2.2 - 3 kOhm.
Per entendre com controlar el xip, mirem la descripció de la interfície del dispositiu:
Sí, aquí està, anglès xinès en tota la seva glòria. És problemàtic traduir això, podeu entendre-ho si voleu, però hi ha una altra manera: veure com es descriu la connexió al full de dades amb el TLC5940 tancat funcionalment:
… Només calen tres pins per introduir dades al dispositiu. La vora ascendent del senyal SCLK desplaça les dades del pin SIN al registre intern. Després que s'hagin carregat totes les dades, un breu senyal XLAT alt tanca les dades transferides en sèrie als registres interns. Els registres interns són portes activades pel nivell de senyal XLAT. Totes les dades es transmeten primer MSB.
latch - pestell / pestell / pestell. Bord ascendent és l'avantguarda del pols MSB primer – el bit més significatiu (l'esquerra) endavant. per registrar dades – Transmetre dades seqüencialment (bit a bit).
Paraula pestell sovint es troba a la documentació de xips i es tradueix de diverses maneres, així que per entendre'm ho permetré
petit programa educatiuEl controlador LED és essencialment un registre de desplaçament. "Majús" (canviar) al nom: moviment de dades bit a bit dins del dispositiu: cada nou bit introduït dins empeny tota la cadena cap endavant. Com que ningú vol observar el parpelleig caòtic dels LED durant el torn, el procés té lloc en registres de memòria intermèdia separats dels treballadors per una persiana (pestell) és una mena de vestidor on els bits s'alineen en la seqüència desitjada. Quan tot està a punt, la persiana s'obre i els bits es posen a treballar, substituint el lot anterior. Paraula pestell a la documentació de microcircuits gairebé sempre implica aquest amortidor, en qualsevol combinació que s'utilitzi.
Per tant, la transferència de dades al DM634 es realitza de la següent manera: establiu l'entrada DAI al valor del bit alt del LED llunyà, tireu DCK cap amunt i cap avall; establiu l'entrada DAI al valor del bit següent, tireu DCK; i així successivament fins que s'hagin transmès tots els bits (rellotge), després del qual tirem LAT. Això es pot fer manualmentpoc bang), però és millor utilitzar la interfície SPI especialment afinada per a això, ja que es presenta al nostre STM32 en dues còpies.
Tauleta blava STM32F103
Introducció: els controladors STM32 són molt més complicats que Atmega328 del que poden fer por. Al mateix temps, per raons d'estalvi d'energia, gairebé tots els perifèrics estan desactivats al principi i la freqüència de rellotge és de 8 MHz des d'una font interna. Afortunadament, els programadors de l'STM van escriure un codi que porta el xip als 72 MHz "calculats", i els autors de tots els IDE que conec l'han inclòs en el procediment d'inicialització, de manera que no hem de fer el rellotge (però pots si realment vols). Però cal encendre els perifèrics.
Documentació: el popular xip STM32F103C8T6 està instal·lat a Blue Pill, hi ha dos documents útils per a això:
Full de dades per als microcontroladors STM32F103x8 i STM32F103xB;
Pinouts - pinouts de xip - per si decidim fer taules nosaltres mateixos;
Mapa de memòria: un mapa de memòria per a un xip específic. El Manual de referència té un mapa per a tota la línia, esmenta registres que no són al nostre.
Taula de definicions de pins: llista les funcions de pins principals i alternatives; per a la "píndola blava" a Internet, podeu trobar imatges més convenients amb una llista de pins i les seves funcions. Per tant, de seguida busquem a Google Blue Pill pinout i tenim aquesta imatge a mà:
NB: hi ha hagut un error a la imatge d'Internet, observat als comentaris, pel qual gràcies. La imatge s'ha substituït, però aquesta és una lliçó: és millor comprovar la informació no de les fitxes.
Traiem el full de dades, obrim el Manual de referència, a partir d'ara només el fem servir.
Procediment: tractar l'entrada/sortida estàndard, configurar SPI, encendre els perifèrics necessaris.
D'entrada i sortida
A l'Atmega328, l'E/S és extremadament senzilla, per això l'abundància d'opcions STM32 pot ser confusa. Ara només necessitem conclusions, però fins i tot hi ha quatre opcions:
sortida de drenatge obert, sortida push-pull, alternativa push-pull, alternativa de drenatge obert
"Tirar-empènyer" (push-pull) - la sortida habitual de l'Arduino, el pin pot ser ALTA o BAIXA. Però amb el "desguàs obert" sorgeixen dificultats, encara que de fet tot és senzill aquí:
Configuració de sortida / quan el port s'assigna a la sortida: / buffer de sortida habilitat: / – mode de drenatge obert: "0" al registre de sortida habilita N-MOS, "1" al registre de sortida deixa el port en mode Hi-Z (P -MOS no està activat ) / - Mode push-pull: "0" al registre de sortida activa N-MOS, "1" al registre de sortida activa P-MOS.
Tota la diferència de drenatge obert (desguàs obert) de "empènyer-tirar" (push-pull) és que al primer pin no pot prendre l'estat ALTA: quan s'escriu una unitat al registre de sortida, passa al mode d'alta resistència (alta impedància, Hola-Z). Quan escriu zero, el pin en ambdós modes es comporta igual, tant lògicament com elèctricament.
En el mode de sortida normal, el pin simplement tradueix el contingut del registre de sortida. En "alternativa" està controlat pel perifèric corresponent (vegeu 9.1.4):
Si el bit del port es configura com a sortida de funció alternativa, el registre de sortida es desactiva i el pin es connecta al senyal de sortida del perifèric.
La funcionalitat alternativa de cada pin es descriu a Definicions de pins El full de dades es troba a la imatge descarregada. Quan se li pregunta què fer si el pin té diverses funcions alternatives, la resposta ve donada per una nota a peu de pàgina al full de dades:
Si diversos perifèrics utilitzen el mateix pin, per evitar conflictes entre funcions alternatives, només s'ha d'utilitzar un perifèric alhora, canviant mitjançant el bit d'habilitació del rellotge perifèric (al registre RCC corresponent).
Finalment, els pins en mode de sortida també tenen una velocitat de rellotge. Aquesta és una altra característica d'estalvi d'energia, en el nostre cas només la posem al màxim i l'oblidem.
Per tant: estem utilitzant SPI, el que significa que dos pins (amb dades i amb un senyal de rellotge) haurien de ser "funció push-pull alternativa", i un més (LAT) hauria de ser "push-pull normal". Però abans d'assignar-los, parlem de SPI.
SCI
Un altre petit truc
SPI o Serial Peripheral Interface (interfície perifèrica sèrie) és una interfície senzilla i molt eficaç per comunicar MK amb altres MK i amb el món exterior en general. El principi del seu funcionament ja s'ha descrit anteriorment, pel que fa al controlador LED xinès (vegeu la secció 25 del manual de referència). SPI pot funcionar en modes mestre ("mestre") i esclau ("esclau"). SPI té quatre canals bàsics, dels quals no tots poden estar implicats:
MOSI, sortida mestre / entrada esclau: aquest pin envia dades en mode mestre i rep dades en mode esclau;
MISO, Master Input / Slave Output: al contrari, en el mestre que rep, en l'esclau que dóna;
SCK, Serial Clock: estableix la freqüència de transmissió de dades al mestre o rep un senyal de rellotge a l'esclau. Essencialment, beats the beats;
SS, Slave Select: amb aquest canal, l'esclau sap que vol alguna cosa d'ell. A STM32 s'anomena NSS, on N = negatiu, és a dir. el controlador es converteix en esclau si aquest canal té terra. Combina bé amb el mode Open Drain Output, però aquesta és una altra història.
Com tota la resta, SPI a STM32 és ric en funcionalitats, cosa que fa que sigui una mica difícil d'entendre. Per exemple, pot funcionar no només amb SPI, sinó també amb una interfície I2S, i les seves descripcions es barregen a la documentació, cal tallar l'excés de manera oportuna. La nostra tasca és extremadament senzilla: només cal donar dades utilitzant només MOSI i SCK. Anem a l'apartat 25.3.4 (comunicació semidúplex, comunicació semidúplex), on trobem 1 rellotge i 1 cable de dades unidireccional (1 rellotge i 1 flux de dades unidireccional):
En aquest mode, l'aplicació utilitza SPI en mode només de transmissió o només de recepció. / El mode només de transmissió és similar al mode dúplex: les dades es transmeten al pin de transmissió (MOSI en mode mestre o MISO en mode esclau), mentre que el pin de recepció (MISO o MOSI respectivament) es pot utilitzar com a E/S normal. pin. En aquest cas, n'hi ha prou que l'aplicació ignori el buffer Rx (si es llegeix, no hi haurà dades transmeses).
Genial, el pin MISO és lliure, connectem-hi el senyal LAT. Anem a tractar amb Slave Select, que es pot controlar mitjançant programació a STM32, que és molt convenient. Llegim el paràgraf del mateix nom a l'apartat 25.3.1 Descripció general de l'SPI:
Control de programari NSS (SSM = 1) / La informació de selecció d'esclaus es troba al bit SSI del registre SPI_CR1. El pin NSS extern es deixa lliure per a altres necessitats d'aplicació.
És hora d'escriure als registres. Vaig decidir utilitzar SPI2, estem buscant la seva adreça base al full de dades, a la secció 3.3 Mapa de memòria (Mapa de memòria):
Obrim la secció 25.3.3 amb el títol "Configuració de SPI en mode mestre":
1. Estableix el rellotge de la interfície sèrie amb els bits BR[2:0] al registre SPI_CR1.
Els registres es recullen a la secció del manual de referència del mateix nom. Canvi d'adreça (desplaçament d'adreça) CR1 té 0x00, per defecte s'esborren tots els bits (Restableix el valor 0x0000):
Els bits BR configuren el divisor de rellotge del controlador, determinant així la freqüència a la qual funcionarà l'SPI. La freqüència STM32 serà de 72 MHz, el controlador LED, segons el seu full de dades, funciona a una freqüència de fins a 25 MHz, per la qual cosa hem de dividir per quatre (BR[2:0] = 001).
2. Configureu els bits CPOL i CPHA per definir la relació entre la transferència de dades i el rellotge de la interfície sèrie (vegeu el diagrama a la pàgina 240)
Com que estem llegint un full de dades aquí, i no mirant esquemes, mirem més de prop la descripció textual dels bits CPOL i CPHA a la pàgina 704 (Descripció general de l'SPI):
Fase i polaritat del rellotge
Utilitzant els bits CPOL i CPHA del registre SPI_CR1, podeu seleccionar programadament quatre opcions per a les relacions de temporització. El bit CPOL (polaritat del rellotge) controla l'estat del senyal del rellotge quan no es transmeten dades. Aquest bit controla els modes mestre i esclau. Si es restableix CPOL, el pin SCK està baix en repòs. Si el bit CPOL està configurat, el pin SCK és alt quan està inactiu.
Si el bit CPHA (Clock Phase) està establert, l'estroboscopi de trampa MSB és la segona vora del senyal SCK (caiguda si s'esborra CPOL, o front ascendent si CPOL està establert). Les dades es mantenen en el segon canvi de rellotge. Si s'esborra el bit CPHA, l'estroboscopi de trampa de bits alts és el front ascendent del senyal SCK (caiguda si s'estableix CPOL, o front ascendent si CPOL està clar). Les dades es mantenen en el primer canvi de rellotge.
Havent tastat aquest coneixement, arribem a la conclusió que tots dos bits han de romandre zero, perquè volem que el senyal SCK es mantingui baix quan no s'utilitzi i que les dades es transmetin al front ascendent del pols (vegeu la fig. Bord ascendent al full de dades DM634).
Per cert, aquí ens vam trobar per primera vegada amb una característica del vocabulari a les fitxes de dades ST: en elles s'escriu la frase "restableix el bit a zero" per reiniciar una micaI no per aclarir una mica, com, per exemple, Atmega.
3. Estableix el bit DFF per determinar el format del bloc de dades de 8 o 16 bits
He agafat específicament el DM16 de 634 bits per no molestar-me amb la transferència de dades PWM de 12 bits, com el DM633. DFF té sentit posar la unitat:
4. Configureu el bit LSBFIRST al registre SPI_CR1 per definir el format de bloc
LSBFIRST, com el seu nom indica, configura primer la transmissió amb el bit menys significatiu. Però el DM634 vol rebre dades MSB primer. Per tant, ho deixem reset.
5. En el mode de maquinari, si cal l'entrada del pin NSS, conduïu el pin NSS alt durant tota la seqüència de transferència de bytes. En el mode de programa NSS, establiu els bits SSM i SSI al registre SPI_CR1. Si s'ha de sortir el pin NSS, només cal configurar el bit SSOE.
Instal·leu SSM i SSI per oblidar-vos del mode de maquinari NSS:
#define SSI 0x0100
#define SSM 0x0200
_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high
6. S'han d'establir els bits MSTR i SPE (només es mantenen si el NSS és alt)
De fet, amb aquests bits assignem el nostre SPI com a mestre i l'activem:
SPI està configurat, escrivim immediatament funcions que enviïn bytes al controlador. Continueu llegint 25.3.3 "Configuració de SPI en mode mestre":
Ordre de transferència de dades
La transferència comença quan s'escriu un byte al buffer Tx.
El byte de dades es carrega al registre de desplaçament a paral·lel mode (des del bus intern) durant la transmissió del primer bit, després del qual es transmet consistent Mode pin MOSI, primer o últim bit cap endavant en funció de la configuració del bit LSBFIRST al registre CPI_CR1. La marca TXE s'estableix després de la transmissió de dades de la memòria intermèdia Tx al registre de canvi, i es genera una interrupció si s'estableix el bit TXEIE del registre CPI_CR1.
He destacat algunes paraules a la traducció per cridar l'atenció sobre una característica de la implementació de SPI als controladors STM. A l'Atmega, la bandera TXE (Tx buit, Tx està buit i llest per rebre dades) només s'estableix després que s'hagi enviat tot el byte cap a fora. I aquí aquesta bandera s'estableix després que el byte s'hagi introduït al registre de desplaçament intern. Com que s'introdueix allà amb tots els bits al mateix temps (en paral·lel), i després les dades es transmeten seqüencialment, el TXE s'estableix abans que el byte s'enviï completament. Això és important perquè en el cas del nostre controlador LED, hem de treure el pin LAT després de l'enviament Tot dades, és a dir. només la bandera TXE no ens serà suficient.
Això vol dir que necessitem una altra bandera. Vegem la 25.3.7 - "Marques d'estat":
<...>
Bandera OCUPADA
El maquinari estableix i esborra el senyalador BSY (escriure-hi no té cap efecte). La bandera BSY indica l'estat de la capa de comunicació SPI.
Es reinicia:
quan s'hagi completat la transferència (excepte en mode mestre si la transferència és contínua)
quan SPI està desactivat
quan es produeix un error de mode mestre (MODF=1)
Si la transmissió no és contínua, el senyalador BSY s'esborra entre cada transmissió de dades.
D'acord, serà útil. Esbrineu on es troba el buffer Tx. Per fer-ho, llegiu el "Registre de dades SPI":
Bits 15:0 DR[15:0] Registre de dades
Dades rebudes o dades a transmetre.
El registre de dades es divideix en dos buffers, un d'escriptura (búfer de transmissió) i un altre de lectura (búfer de recepció). Una escriptura al registre de dades escriu a la memòria intermèdia Tx, i una lectura des del registre de dades retornarà el valor contingut a la memòria intermèdia Rx.
Bé, el registre d'estat, on hi ha senyals TXE i BSY:
Bé, com que necessitem transferir 16 vegades dos bytes, segons el nombre de sortides del controlador LED, una cosa així:
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();
}
Però encara no sabem com treure el pin LAT, així que tornem a l'E/S.
Assigna pins
A STM32F1, els registres responsables de l'estat dels pins són força inusuals. Està clar que n'hi ha més que Atmega, però també són diferents d'altres xips STM. Secció 9.1 Descripció general de GPIO:
Cadascun dels ports d'E/S de propòsit general (GPIO) té dos registres de configuració de 32 bits (GPIOx_CRL i GPIOx_CRH), dos registres de dades de 32 bits (GPIOx_IDR i GPIOx_ODR), un registre d'establiment/restabliment de 32 bits (GPIOx_BSRR), un registre de restabliment de 16 bits (GPIOx_BRR) i un registre de 32 bits. registre de bloqueig de bits (GPIOx_LCKR).
Els dos primers registres aquí són inusuals, i també bastant inconvenients, perquè els 16 pins del port estan escampats per ells en un format de "quatre bits per germà". Aquells. els pins del XNUMX al XNUMX es troben a CRL i la resta es troben a CRH. Al mateix temps, els registres restants s'ajusten correctament als bits de tots els pins del port, sovint quedant la meitat "reservats".
Per simplificar, comencem pel final de la llista.
No necessitem un registre de bloqueig.
Els registres de configuració i restabliment són bastant divertits, ja que es dupliquen parcialment entre si: només podeu escriure-ho tot en BSRR, on els 16 bits superiors restabliran el pin a zero i els inferiors es posaran a 1, o també podeu utilitzeu BRR, els 16 bits inferiors dels quals només restabliten el pin . M'agrada la segona opció. Aquests registres són importants perquè proporcionen accés atòmic als pins:
Instal·lació o restabliment atòmic
No cal que desactiveu les interrupcions quan programeu GPIOx_ODR a nivell de bits: podeu canviar un o més bits amb una única operació d'escriptura atòmica APB2. Això s'aconsegueix escrivint un "1" al registre set/reset (GPIOx_BSRR o, només per a reiniciar, GPIOx_BRR) del bit que s'ha de canviar. Els altres bits romandran sense canvis.
Els registres de dades tenen noms bastant parlants - IDR = entrada Registre de direcció, registre d'entrada; ODR= sortida Registre de direcció, registre de sortida. En el projecte actual, no els necessitem.
I finalment, els registres de control. Com que estem interessats en els pins del segon SPI, és a dir, PB13, PB14 i PB15, de seguida mirem CRH:
I veiem que caldrà escriure alguna cosa a trossets del 20 al 31.
Ja hem descobert què volem dels pins anteriors, així que aquí faré sense cap captura de pantalla, només digues que MODE estableix la direcció (entrada si els dos bits estan configurats a 0) i la velocitat del pin (necessitem 50MHz, és a dir. tots dos pins a "1"), i CNF estableix el mode: normal "push-push" - 00, "alternatiu" - 10. Per defecte, com podem veure més amunt, tots els pins tenen el tercer bit des de la part inferior ( CNF0), els posa en mode entrada flotant.
Com que penso fer alguna cosa més amb aquest xip, per simplificar, generalment he definit tots els valors MODE i CNF possibles tant per als registres de control inferior com superior.
(LAT_low només per inèrcia, d'alguna manera sempre ho va ser, deixa que es quedi per tu)
Ara tot està genial, simplement no funciona. Com que es tracta de STM32, aquí estalvien electricitat, la qual cosa significa que cal activar el rellotge dels perifèrics necessaris.
Activa el rellotge
El rellotge és el responsable del rellotge, també són el rellotge. I ja vam poder notar l'abreviatura RCC. Ho busquem a la documentació: es tracta de Reset and Clock Control (Gestió de reset i clock).
Com s'ha dit més amunt, afortunadament, la gent de STM ens va fer la part més difícil del tema del cronometratge, per la qual cosa a ells moltes gràcies (de nou us donaré un enllaç a Lloc web de Di Haltper deixar clar el confós que està). Només necessitem registres responsables d'habilitar el rellotge perifèric (Peripheral Clock Enable Registers). Primer, busquem l'adreça base del RCC, és al principi de la "Targeta de memòria":
I després feu clic a l'enllaç on intentar trobar alguna cosa a la taula o, molt millor, repasseu les descripcions dels registres inclosos de les seccions sobre habilitar els registres. On trobem RCC_APB1ENR i RCC_APB2ENR:
I en ells, respectivament, bits que inclouen el clock de SPI2, IOPB (I/O Port B) i funcions alternatives (AFIO).
Si hi ha una oportunitat i ganes de provar, connectem el DM634 així: DAI a PB15, DCK a PB13, LAT a PB14. Alimentem el conductor des de 5 volts, no us oblideu de combinar els terrenys.
STM8 PWM
PWM a STM8
Quan estava planejant aquest article, vaig decidir, per exemple, intentar dominar alguna funcionalitat d'un xip desconegut només amb l'ajuda d'un full de dades, de manera que un sabater no sortiria sense botes. STM8 era perfecte per a aquest paper: en primer lloc, tenia un parell de taulers xinesos amb STM8S103 i, en segon lloc, no és molt popular i, per tant, la temptació de llegir i trobar una solució a Internet es basa en l'absència d'aquestes mateixes solucions.
Per defecte, STM8 funciona a una freqüència de 2 MHz, això s'ha de corregir immediatament.
Rellotge HSI (alt intern)
El rellotge HSI es deriva d'un oscil·lador RC intern de 16 MHz amb un divisor programable (1 a 8). S'estableix al registre divisor del rellotge (CLK_CKDIVR).
Nota: l'oscil·lador HSI RC amb un divisor de 8 es selecciona com a font de rellotge mestre a l'inici.
Trobem l'adreça del registre al full de dades, la descripció a refman i veiem que cal esborrar el registre:
Com que executarem PWM i connectarem LED, mirem el pinout:
El xip és petit, moltes funcions estan suspeses als mateixos pins. El que està entre claudàtors és "funcionalitat alternativa", es canvia per "bytes d'opció" (bytes d'opció) - una cosa com els fusibles Atmega. Podeu canviar els seus valors de manera programada, però no és necessari, perquè. La nova funcionalitat només s'activa després d'un reinici. És més fàcil utilitzar ST Visual Programmer (descarregat amb Visual Develop), que pot canviar aquests bytes. El pinout mostra que les sortides CH1 i CH2 del primer temporitzador estan amagades entre claudàtors; cal configurar els bits AFR1 i AFR0 a STVP, i el segon també transferirà la sortida CH1 del segon temporitzador de PD4 a PC5.
Així, 6 pins controlaran els LED: PC6, PC7 i PC3 per al primer temporitzador, PC5, PD3 i PA3 per al segon.
Configurar els pins d'E/S a l'STM8 és més senzill i lògic que a l'STM32:
Registre de direcció de dades familiar Atmega DDR (Registre de direcció de dades): 1 = sortida;
el primer registre de control CR1, quan surt, estableix el mode push-pull (1) o drenatge obert (0); com que connecto els LED al xip amb càtodes, aquí deixo zeros;
el segon registre de control CR2 estableix la velocitat de rellotge en sortir: 1 = 10 MHz
Freqüència PWM – freqüència amb què el temporitzador funciona;
Recàrrega automàtica, AR – valor carregat automàticament, fins al qual comptarà el temporitzador (període de pols);
Esdeveniment d'actualització, UEV – un esdeveniment que es produeix quan el temporitzador ha comptat fins a AR;
Cicle de treball PWM - Cicle de treball PWM, sovint anomenat "cicle de treball";
Captura/Compara el valor – valor per capturar/comparar, comptant fins al qual el temporitzador farà alguna cosa (en el cas de PWM, inverteix el senyal de sortida);
valor de precàrrega - valor precarregat. comparar el valor no pot canviar mentre el temporitzador està en marxa, en cas contrari el cicle PWM es trencarà. Per tant, els nous valors transmesos es col·loquen a la memòria intermèdia i es treuen quan el temporitzador arriba al final del compte enrere i es reinicia;
Alineat amb les vores и Modes alineats al centre – alineació a la vora i al centre, igual que atmelovskie PWM ràpid и PWM de fase correcta.
OCiREF, senyal de referència de comparació de sortida - el senyal de sortida de referència, de fet, el que apareix al pin corresponent en mode PWM.
Com ja queda clar a partir del pinout, dos temporitzadors tenen capacitats PWM: el primer i el segon. Tots dos són de 16 bits, el primer té moltes funcions addicionals (en particular, pot comptar tant amunt com a baix). Necessitem que tots dos funcionin de la mateixa manera, així que vaig decidir començar pel segon, òbviament, més pobre, per no utilitzar accidentalment quelcom que no hi és. Algun problema és que la descripció de la funcionalitat PWM de tots els temporitzadors al manual de referència es troba al capítol sobre el primer temporitzador (mode 17.5.7 PWM), de manera que heu de saltar cap endavant i cap enrere pel document tot el temps.
PWM a STM8 té un avantatge important sobre Atmega PWM:
PWM amb alineació de vores
Configuració del compte de baix a dalt
El recompte està actiu si el bit DIR del registre TIM_CR1 està clar
Exemple
L'exemple utilitza el primer mode PWM. El senyal de referència PWM OCiREF es manté alt mentre TIM1_CNT < TIM1_CCRi. En cas contrari, es necessita un nivell baix. Si el valor a comparar al registre TIM1_CCRi és més gran que el valor de càrrega automàtica (registre TIM1_ARR), el senyal OCiREF es manté a 1. Si el valor de comparació és 0, OCiREF es manté a zero....
Temporitzador STM8 durant esdeveniment d'actualització comprova primer comparar el valor, i només llavors produeix un senyal de referència. A Atmega, el temporitzador primer tremola, i després es compara, com a resultat, quan compare value == 0 la sortida és una agulla que s'ha de tractar d'alguna manera (per exemple, invertint la lògica programadament).
Aleshores, què volem fer: PWM de 8 bits (AR == 255), comptant de baix a dalt, alineació al llarg de la vora. Com que les bombetes estan connectades al xip mitjançant càtodes, el PWM hauria de sortir 0 (LED encès) fins que comparar el valor i 1 després.
Ja n'hem llegit sobre alguns Mode PWM, així trobem el registre desitjat del segon temporitzador cercant al manual de referència aquesta frase (18.6.8 - TIMx_CCMR1):
110: Primer mode PWM: quan es compta de baix a dalt, el primer canal està actiu sempre que TIMx_CNT < TIMx_CCR1. En cas contrari, el primer canal està inactiu. [més al document, còpia-enganxa errònia del temporitzador 1] 111: Segon mode PWM: quan es compta de baix a dalt, el primer canal està inactiu fins que TIMx_CNT < TIMx_CCR1. En cas contrari, el primer canal està actiu.
Com que els LED estan connectats al MK amb càtodes, el segon mode ens convé (el primer també, però això encara no ho sabem).
Bit 3 OC1PE: Habilita la sortida de precàrrega 1
0: Registre de precàrrega a TIMx_CCR1 desactivat. Podeu escriure a TIMx_CCR1 en qualsevol moment. El nou valor funciona immediatament.
1: Registre de precàrrega a TIMx_CCR1 habilitat. Les operacions de lectura/escriptura accedeixen al registre de precàrrega. El valor precarregat de TIMx_CCR1 es carrega al registre d'ombra durant cada esdeveniment d'actualització.
*Nota: els registres de precàrrega s'han d'habilitar perquè el mode PWM funcioni correctament. Això és opcional en mode de senyal únic (el bit OPM s'estableix al registre TIMx_CR1).
D'acord, activeu tot el que necessiteu per als tres canals del segon temporitzador:
El segon temporitzador només pot comptar de baix a dalt, alineació a la vora, no cal canviar res. Estableix el divisor de freqüència, per exemple, a 256. Per al segon temporitzador, el divisor s'estableix al registre TIM2_PSCR i té una potència de dos:
Queda per activar les conclusions i el segon temporitzador en si. La primera tasca es resol mitjançant registres Captura/Compara Enable: n'hi ha dos, tres canals estan escampats asimètricament per sobre d'ells. Aquí també podem aprendre que és possible canviar la polaritat del senyal, és a dir. en principi, també es podria utilitzar el mode PWM 1. Escrivim:
Escrivim un anàleg senzill d'AnalogWrite (), que passarà els valors reals al temporitzador per a la seva comparació. Els registres tenen un nom previsible Captura/Compara registres, n'hi ha dos per a cada canal: els 8 bits baixos a TIM2_CCRxL i els bits alts a TIM2_CCRxH. Com que vam començar PWM de 8 bits, n'hi ha prou amb escriure només els bits baixos:
El lector atent notarà que tenim un PWM lleugerament defectuós, incapaç d'omplir el 100% (a un valor màxim de 255, el senyal s'inverteix per un cicle de temporitzador). Per als LED, això no té cap paper, i el lector atent ja endevina com solucionar-ho.
PWM al segon temporitzador funciona, aneu al primer.
El primer temporitzador té exactament els mateixos bits en els mateixos registres (és que els bits que van quedar "reservats" en el segon temporitzador s'utilitzen activament per a tot tipus de coses avançades en el primer). Per tant, n'hi ha prou amb trobar les adreces dels mateixos registres al full de dades i copiar el codi. Bé, canvieu el valor del divisor de freqüència, perquè. el primer temporitzador no vol obtenir una potència de dos, sinó un valor exacte de 16 bits en dos registres Preescalador alt и Sota. Ho fem de tot i... el primer temporitzador no funciona. Què passa?
L'única manera de resoldre el problema és mirant tota la secció sobre els registres de control del temporitzador 1, on estem buscant un que el segon temporitzador no té. hi haurà 17.7.30 Pausa registre (TIM1_BKR), on hi ha una mica com això:
El tercer mini-projecte consisteix a connectar vuit LED RGB al segon temporitzador en mode PWM i fer que mostrin diferents colors. Es basa en el concepte de multiplexació de LED, que consisteix en que si s'encenen i apaguen els LED molt i molt ràpidament, ens semblarà que estan enceses constantment (persistència de la visió, inèrcia de la percepció visual). Una vegada ho vaig fer alguna cosa així a l'arduino.
L'algorisme de treball té aquest aspecte:
connectat l'ànode del primer LED RGB;
encendre-lo donant els senyals necessaris als càtodes;
va esperar el final del cicle PWM;
connectat l'ànode del segon LED RGB;
l'enceneu...
Bé, etc. Per descomptat, per a un treball bonic, cal que la connexió de l'ànode i l'"encesa" del LED es produeixin simultàniament. Bé, gairebé. En qualsevol cas, hem d'escriure un codi que sortirà valors en tres canals del segon temporitzador, canviar-los quan s'arribi a la UEV i, alhora, canviar el LED RGB actiu actualment.
Com que el canvi de LED és automàtic, heu de crear "memòria de vídeo" des d'on el gestor d'interrupcions rebrà dades. Aquesta és una matriu senzilla:
uint8_t colors[8][3];
Per canviar el color d'un LED determinat, n'hi haurà prou amb escriure els valors necessaris en aquesta matriu. I la variable serà responsable del nombre del LED actiu
uint8_t cnt;
Demux
Per a una multiplexació adequada, necessitem, curiosament, el demultiplexor CD74HC238. Demultiplexer - un xip que implementa l'operador en el maquinari <<. A través de tres pins d'entrada (bits 0, 1 i 2) li alimentem un número X de tres bits, i en resposta activa el número de sortida (1<<X). Les entrades restants del xip s'utilitzen per escalar tot el disseny. Necessitem aquest xip no només per reduir el nombre de pins ocupats del microcontrolador, sinó també per seguretat, per no encendre accidentalment més LED del possible i no cremar el MK. El xip costa un cèntim, s'ha de guardar sempre a la farmaciola de casa.
CD74HC238 serà l'encarregat de subministrar tensió a l'ànode del LED desitjat. En un múltiplex complet, subministraria tensió a la columna a través del P-MOSFET, però en aquesta demostració, ho podeu fer directament, perquè. tira 20mA, segons qualificacions màximes absolutes al full de dades. Des de Full de dades CD74HC238 necessitem un pinout i aquest full de trucs:
H = nivell d'alta tensió, L = nivell de baixa tensió, X - no m'importa
Connectem E2 i E1 a terra, E3, A0, A1 i A3 als pins PD5, PC3, PC4 i PC5 de STM8. Com que la taula anterior conté nivells alts i baixos, hem configurat aquests pins com a pins push-pull.
PWM
El PWM del segon temporitzador es configura de la mateixa manera que a la història anterior, amb dues diferències:
En primer lloc, hem d'activar la interrupció Esdeveniment d'actualització (UEV) que cridarà una funció per canviar el LED actiu. Això es fa canviant el bit Actualitzar la interrupció activada en un registre amb un nom parlant
La segona diferència està relacionada amb un fenomen de multiplexació com l'efecte fantasma - resplendor paràsit dels díodes. En el nostre cas, pot semblar que el temporitzador, després d'haver provocat una interrupció a l'UEV, continua funcionant i el controlador d'interrupcions no té temps per canviar el LED abans que el temporitzador comenci a escriure alguna cosa a les sortides. Per combatre-ho, haureu d'invertir la lògica (0 = brillantor màxima, 255 = no hi ha res activat) i no permetre valors de cicle de treball extrems. Aquells. Assegureu-vos que després de la UEV els LED s'apaguin completament durant un cicle PWM.
Eviteu establir r, g i b a 255 i recordeu invertir-los quan feu servir.
Interrupcions
L'essència de la interrupció és que, en determinades circumstàncies, el xip deixa d'executar el programa principal i crida alguna funció externa. Les interrupcions es produeixen a causa d'influències externes o internes, inclosa la del temporitzador.
Quan vam crear per primera vegada un projecte a ST Visual Develop, a part de main.c tenim una finestra amb un fitxer misteriós stm8_interrupt_vector.cautomàticament inclòs en el projecte. En aquest fitxer, s'adjunta una funció a cada interrupció NonHandledInterrupt. Hem d'enllaçar la nostra funció a la interrupció desitjada.
El full de dades té una taula de vectors d'interrupció, on trobem els que necessitem:
13 Actualització/desbordament de TIM2
14 TIM2 Captura/Comparació
Hem de canviar el LED a UEV, de manera que cal la interrupció #13.
En conseqüència, en primer lloc, a l'expedient stm8_interrupt_vector.c canviar el nom de la funció responsable de la interrupció número 13 (IRQ13) per defecte pel nostre:
{0x82, TIM2_Overflow}, /* irq13 */
En segon lloc, haurem de crear un fitxer main.h contingut com aquest:
I, finalment, escriviu aquesta funció al vostre 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;
}
Queda per habilitar les interrupcions. Això es fa amb una ordre assemblador. rim - l'hauràs de buscar Manual de programació:
//enable interrupts
_asm("rim");
Una altra instrucció del muntador - sim - Desactiva les interrupcions. S'han de desactivar mentre s'escriuen nous valors a la "memòria de vídeo" perquè una interrupció provocada en un moment desafortunat no faci malbé la matriu.