Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Π’ sehemu ya kwanza Nilijaribu kuwaambia wahandisi wa vifaa vya elektroniki vya hobby ambao walikua kutoka kwa suruali ya Arduino jinsi na kwa nini wanapaswa kusoma hifadhidata na nyaraka zingine za vidhibiti vidogo. Maandishi yaligeuka kuwa makubwa, kwa hiyo niliahidi kuonyesha mifano ya vitendo katika makala tofauti. Kweli, alijiita uyoga wa maziwa ...

Leo nitakuonyesha jinsi ya kutumia hifadhidata kutatua rahisi sana, lakini muhimu kwa miradi mingi, kazi kwenye STM32 (Kidonge cha Bluu) na vidhibiti vya STM8. Miradi yote ya demo imejitolea kwa LED zangu zinazopenda, tutawaangazia kwa kiasi kikubwa, ambayo tutalazimika kutumia kila aina ya pembeni za kuvutia.

Maandishi tena yaligeuka kuwa makubwa, kwa hivyo kwa urahisi ninatayarisha yaliyomo:

Kidonge cha Bluu cha STM32: LEDs 16 zenye kiendeshi cha DM634
STM8: Kuweka pini sita za PWM
STM8: LED za RGB 8 kwenye pini tatu, hukatiza

Kanusho: Mimi si mhandisi, sijifanyi kuwa nina maarifa ya kina katika vifaa vya elektroniki, nakala hiyo imekusudiwa wafadhili kama mimi. Kwa kweli, nilijiona miaka miwili iliyopita kama walengwa. Ikiwa mtu angeniambia basi kwamba hifadhidata kwenye chip isiyojulikana hazikutisha kusoma, nisingetumia muda mwingi kutafuta vipande vya msimbo kwenye Mtandao na kuvumbua magongo yenye mkasi na mkanda wa wambiso.

Lengo la kifungu hiki ni kwenye hifadhidata, sio miradi, kwa hivyo msimbo unaweza kuwa sio safi sana na mara nyingi ni duni. Miradi yenyewe ni rahisi sana, ingawa inafaa kwa kufahamiana kwa kwanza na chip mpya.

Natumaini kwamba makala yangu itasaidia mtu katika hatua sawa ya kuzamishwa katika hobby.

ST32

LEDs 16 zenye DM634 na SPI

Mradi mdogo unaotumia Kidonge cha Bluu (STM32F103C8T6) na kiendeshi cha LED DM634. Kwa kutumia hifadhidata, tutagundua dereva, bandari za STM IO na kusanidi SPI.

DM634

Chip ya Taiwan yenye matokeo 16 ya 16-bit PWM, inaweza kuunganishwa kwa minyororo. Mfano wa chini wa 12-bit unajulikana kutoka kwa mradi wa ndani Lightpack. Wakati mmoja, kuchagua kati ya DM63x na TLC5940 inayojulikana, nilichagua DM kwa sababu kadhaa: 1) TLC kwenye Aliexpress ni dhahiri bandia, lakini hii sio; 2) DM ina PWM ya uhuru na jenereta yake ya mzunguko; 3) inaweza kununuliwa kwa gharama nafuu huko Moscow, badala ya kusubiri sehemu kutoka kwa Ali. Na, bila shaka, ilikuwa ya kuvutia kujifunza jinsi ya kudhibiti chip mwenyewe, badala ya kutumia maktaba iliyopangwa tayari. Chips sasa zinawasilishwa hasa katika kifurushi cha SSOP24; ni rahisi kuuzwa kwa adapta.

Kwa kuwa mtengenezaji ni wa Taiwan, karatasi ya data chip imeandikwa kwa Kiingereza cha Kichina, ambayo inamaanisha itakuwa ya kufurahisha. Kwanza tunaangalia pinout (Muunganisho wa Pini) kuelewa ni mguu gani wa kuunganisha nini, na maelezo ya pini (Maelezo ya Pini) 16 pini:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Vyanzo vya Kuzama vya DC (Mfereji wa maji wazi)

Punguza / Pato la mkondo wa wazi - kukimbia; chanzo cha mtiririko wa maji; pato ni kushikamana na ardhi katika hali ya kazi - LEDs ni kushikamana na dereva na cathodes. Kwa umeme, hii, kwa kweli, sio "mifereji ya maji wazi" (fungua bomba), lakini katika hifadhidata jina hili la pini katika hali ya kukimbia mara nyingi hupatikana.

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Vipinga vya nje kati ya REXT na GND ili kuweka thamani ya sasa ya pato

Kipinga marejeleo kimewekwa kati ya pini ya REXT na ardhi, ambayo inadhibiti upinzani wa ndani wa matokeo, angalia grafu kwenye ukurasa wa 9 wa hifadhidata. Katika DM634, upinzani huu pia unaweza kudhibitiwa na programu, kuweka mwangaza wa jumla (mwangaza wa kimataifa); Sitaingia katika maelezo katika makala hii, nitaweka tu kupinga 2.2 - 3 kOhm hapa.

Ili kuelewa jinsi ya kudhibiti chip, hebu tuangalie maelezo ya kiolesura cha kifaa:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Ndio, hii hapa, Kiingereza cha Kichina katika utukufu wake wote. Kutafsiri hii ni shida, unaweza kuielewa ikiwa unataka, lakini kuna njia nyingine - angalia jinsi unganisho la TLC5940 inayofanya kazi inavyofafanuliwa kwenye hifadhidata:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
... Pini tatu tu zinahitajika ili kuingiza data kwenye kifaa. Makali ya kuongezeka kwa ishara ya SCLK huhamisha data kutoka kwa pini ya SIN hadi rejista ya ndani. Baada ya data zote kupakiwa, ishara fupi ya juu ya XLAT hufunga data iliyohamishwa kwa mfuatano kwenye rejista za ndani. Daftari za ndani ni milango inayosababishwa na kiwango cha ishara cha XLAT. Data zote hupitishwa muhimu zaidi kwanza.

Latch – latch/latch/lock.
Kupanda kwa makali - makali ya mbele ya mapigo
MSB kwanza - muhimu zaidi (kushoto) mbele kidogo.
kwa data ya saa - Sambaza data kwa mfuatano (kidogo kidogo).

Neno latch mara nyingi hupatikana katika nyaraka za chips na hutafsiriwa kwa njia mbalimbali, kwa hiyo kwa ajili ya kuelewa nitajiruhusu

programu ndogo ya elimuKiendeshaji cha LED kimsingi ni rejista ya mabadiliko. "Shift" (kuhama) kwa jina - mwendo wa data kwa busara ndani ya kifaa: kila biti mpya inayosukumwa ndani husukuma mnyororo mzima mbele yake. Kwa kuwa hakuna mtu anataka kuona kufumba kwa taabu kwa taa za LED wakati wa zamu, mchakato huo unafanyika katika rejista za bafa zilizotenganishwa na rejista za kufanya kazi na damper (latch) ni aina ya chumba cha kusubiri ambapo bits hupangwa katika mlolongo unaohitajika. Wakati kila kitu kiko tayari, shutter inafungua na bits kwenda kufanya kazi, kuchukua nafasi ya kundi la awali. Neno latch katika nyaraka za microcircuits karibu daima ina maana damper vile, bila kujali ni mchanganyiko gani hutumiwa.

Kwa hivyo, uhamishaji wa data kwa DM634 unafanywa kama hii: kuweka pembejeo ya DAI kwa thamani ya sehemu muhimu zaidi ya LED ya mbali, vuta DCK juu na chini; weka pembejeo ya DAI kwa thamani ya kidogo inayofuata, vuta DCK; na kadhalika hadi biti zote zimepitishwa (akaingia), baada ya hapo tunavuta LAT. Hii inaweza kufanywa kwa mikono (kidogo-bang), lakini ni bora kutumia interface ya SPI iliyoundwa mahsusi kwa hili, kwani imewasilishwa kwenye STM32 yetu katika nakala mbili.

Kidonge cha Bluu STM32F103

Utangulizi: Vidhibiti vya STM32 ni ngumu zaidi kuliko Atmega328 kuliko vinaweza kuonekana kuwa vya kutisha. Zaidi ya hayo, kwa sababu za kuokoa nishati, karibu vifaa vyote vya pembeni vimezimwa mwanzoni, na mzunguko wa saa ni 8 MHz kutoka kwa chanzo cha ndani. Kwa bahati nzuri, waandaaji wa programu za STM waliandika msimbo ambao huleta chip hadi "iliyohesabiwa" 72 MHz, na waandishi wa IDE zote ninazojua waliijumuisha katika utaratibu wa uanzishaji, kwa hivyo hatuitaji saa (lakini unaweza kama kweli unataka) Lakini itabidi uwashe vifaa vya pembeni.

Nyaraka: Kidonge cha Bluu kimewekwa na chip maarufu cha STM32F103C8T6, kuna hati mbili muhimu kwa hiyo:

Katika hifadhidata tunaweza kupendezwa na:

  • Pinouts - chip pinouts - ikiwa tutaamua kutengeneza bodi wenyewe;
  • Ramani ya Kumbukumbu - ramani ya kumbukumbu kwa chip maalum. Mwongozo wa Marejeleo una ramani ya mstari mzima, na unataja rejista ambazo zetu hazina.
  • Jedwali la Ufafanuzi wa Pini - kuorodhesha kazi kuu na mbadala za pini; kwa "kidonge cha bluu" unaweza kupata picha zinazofaa zaidi kwenye mtandao na orodha ya pini na kazi zao. Kwa hivyo, mara moja tunatafuta kidonge cha Blue Pill na kuweka picha hii karibu:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
NB: kulikuwa na hitilafu kwenye picha kutoka kwenye mtandao, ambayo ilibainishwa kwenye maoni, asante kwa hilo. Picha imebadilishwa, lakini hii ni somo - ni bora kuangalia habari sio kutoka kwa hifadhidata.

Tunaondoa hifadhidata, kufungua Mwongozo wa Marejeleo, na kuanzia sasa tunaitumia tu.
Utaratibu: tunashughulika na pembejeo / pato la kawaida, sanidi SPI, washa vifaa vya pembeni muhimu.

Ingizo

Kwenye Atmega328, I/O inatekelezwa kwa urahisi sana, ndiyo sababu wingi wa chaguzi za STM32 zinaweza kutatanisha. Sasa tunahitaji tu hitimisho, lakini hata hizi zina chaguzi nne:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
fungua mifereji ya maji, sukuma-vuta, sukuma-vuta mbadala, bomba mbadala wazi

"Vuta-sukuma" (sukuma-vuta) ni pato la kawaida kutoka kwa Arduino, pini inaweza kuchukua thamani ama HIGH au LOW. Lakini kwa "kukimbia wazi" kuna matatizo, ingawa kwa kweli kila kitu ni rahisi hapa:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Usanidi wa pato / wakati bandari imepewa pato: / bafa ya pato imewezeshwa: / - fungua hali ya kukimbia: "0" kwenye rejista ya pato huwezesha N-MOS, "1" kwenye rejista ya pato huacha bandari katika hali ya Hi-Z ( P-MOS haijaamilishwa ) / – hali ya kusukuma-kuvuta: "0" kwenye rejista ya pato huwasha N-MOS, "1" kwenye rejista ya pato huwasha P-MOS.

Tofauti zote kati ya kukimbia wazi (fungua bomba) kutoka kwa β€œsukuma-vuta” (sukuma-vuta) ni kwamba katika pini ya kwanza haiwezi kukubali hali ya HIGH: wakati wa kuandika moja kwa rejista ya pato, huenda kwenye hali ya juu ya upinzani (high impedance, Hi-Z) Wakati wa kuandika sifuri, pini hufanya sawa katika njia zote mbili, kwa mantiki na kwa umeme.

Katika hali ya kawaida ya pato, pini inatangaza tu yaliyomo kwenye rejista ya pato. Katika "mbadala" inadhibitiwa na vifaa vya pembeni vinavyolingana (ona 9.1.4):

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Ikiwa biti la mlango litawekwa kama pini mbadala ya kukokotoa, rejista ya pini itazimwa na pini itaunganishwa kwenye pini ya pembeni.

Utendaji mbadala wa kila pini umeelezewa ndani Ufafanuzi wa Pini Hifadhidata iko kwenye picha iliyopakuliwa. Kwa swali la nini cha kufanya ikiwa pini ina kazi kadhaa mbadala, jibu linatolewa na maelezo ya chini kwenye hifadhidata:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Iwapo vifaa vingi vya pembeni vitatumia pini moja, ili kuepuka mgongano kati ya vitendakazi mbadala, ni kifaa kimoja tu cha pembeni kinachopaswa kutumika kwa wakati mmoja, kugeuzwa kwa kutumia saa ya pembeni kuwasha biti (katika rejista ifaayo ya RCC).

Hatimaye, pini katika hali ya pato pia zina kasi ya saa. Hiki ni kipengele kingine cha kuokoa nishati; kwa upande wetu, tunaiweka kwa kiwango cha juu na kuisahau.

Kwa hiyo: tunatumia SPI, ambayo ina maana kwamba pini mbili (zilizo na data na ishara ya saa) zinapaswa kuwa "kazi mbadala ya kusukuma-kuvuta", na nyingine (LAT) inapaswa kuwa "kusukuma-kuvuta mara kwa mara". Lakini kabla ya kuwakabidhi, wacha tushughulike na SPI.

SPI

Mpango mwingine mdogo wa elimu

SPI au Serial Peripheral Interface (kiolesura cha pembeni cha mfululizo) ni kiolesura rahisi na kizuri sana cha kuunganisha MK na MK zingine na ulimwengu wa nje kwa ujumla. Kanuni ya uendeshaji wake tayari imeelezwa hapo juu, ambapo kuhusu dereva wa Kichina wa LED (katika mwongozo wa kumbukumbu, angalia sehemu ya 25). SPI inaweza kufanya kazi katika hali ya bwana ("bwana") na mtumwa ("mtumwa"). SPI ina njia nne za kimsingi, ambazo sio zote zinaweza kutumika:

  • MOSI, Pato Kuu / Ingizo la Mtumwa: pini hii inasambaza data katika hali kuu, na kupokea data katika hali ya mtumwa;
  • MISO, Pembejeo ya Mwalimu / Pato la Mtumwa: kinyume chake, inapokea kwa bwana, na kupitisha mtumwa;
  • SCK, Saa ya Saa: huweka mzunguko wa maambukizi ya data kwa bwana au kupokea ishara ya saa katika mtumwa. Kimsingi kupiga beats;
  • SS, Slave Select: kwa msaada wa kituo hiki, mtumwa anajua kwamba kuna kitu kinachohitajika kutoka kwake. Kwenye STM32 inaitwa NSS, ambapo N = hasi, i.e. mtawala anakuwa mtumwa ikiwa kuna msingi katika kituo hiki. Inachanganya vyema na hali ya Open Drain Output, lakini hiyo ni hadithi nyingine.

Kama kila kitu kingine, SPI kwenye STM32 ina utendakazi mwingi, ambayo inafanya kuwa ngumu kuelewa. Kwa mfano, inaweza kufanya kazi si tu kwa SPI, lakini pia kwa interface ya I2S, na katika nyaraka maelezo yao yamechanganywa, ni muhimu kukata ziada kwa wakati unaofaa. Kazi yetu ni rahisi sana: tunahitaji tu kutuma data kwa kutumia MOSI na SCK pekee. Tunaenda kwenye sehemu ya 25.3.4 (mawasiliano ya nusu-duplex, mawasiliano ya nusu-duplex), ambapo tunapata Saa 1 na waya 1 ya data ya unidirectional (mawimbi ya saa 1 na mtiririko 1 wa data unidirectional):

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Katika hali hii, programu hutumia SPI katika hali ya kusambaza pekee au ya kupokea pekee. / Hali ya kutuma pekee inafanana na hali ya duplex: data hupitishwa kwenye pini ya kupitisha (MOSI katika hali kuu au MISO katika hali ya mtumwa), na pini ya kupokea (MISO au MOSI mtawalia) inaweza kutumika kama pini ya kawaida ya I/O. . Katika kesi hii, programu inahitaji tu kupuuza bafa ya Rx (ikiwa inasomwa, hakutakuwa na data iliyohamishwa hapo).

Kubwa, pini ya MISO ni bure, wacha tuunganishe ishara ya LAT nayo. Wacha tuangalie Slave Select, ambayo kwenye STM32 inaweza kudhibitiwa kwa utaratibu, ambayo ni rahisi sana. Tunasoma aya ya jina moja katika sehemu ya 25.3.1 SPI Maelezo ya Jumla:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Udhibiti wa programu NSS (SSM = 1) / Maelezo ya uteuzi wa watumwa yamo katika sehemu ndogo ya SSI ya rejista ya SPI_CR1. Pini ya NSS ya nje inasalia bila malipo kwa mahitaji mengine ya programu.

Ni wakati wa kuandika kwa rejista. Niliamua kutumia SPI2, tafuta anwani yake ya msingi kwenye hifadhidata - katika sehemu ya 3.3 Ramani ya Kumbukumbu:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Kweli, wacha tuanze:

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

Fungua sehemu ya 25.3.3 yenye kichwa kinachojieleza "Kuweka SPI katika Hali Kuu":

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

1. Weka mzunguko wa saa wa mfululizo na biti BR[2:0] kwenye rejista ya SPI_CR1.

Rejesta hukusanywa katika sehemu ya mwongozo ya kumbukumbu ya jina moja. Kuhama kwa anwani (Urekebishaji wa anwani) kwa CR1 - 0x00, kwa chaguo-msingi bits zote zinafutwa (Weka upya thamani 0x0000):

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Biti za BR huweka mgawanyiko wa saa ya mtawala, na hivyo kuamua mzunguko ambao SPI itafanya kazi. Frequency yetu ya STM32 itakuwa 72 MHz, dereva wa LED, kulingana na hifadhidata yake, inafanya kazi na mzunguko wa hadi 25 MHz, kwa hivyo tunahitaji kugawanya na nne (BR[2:0] = 001).

#define _SPI_CR1 0x00

#define BR_0        0x0008
#define BR_1        0x0010
#define BR_2        0x0020

_SPI2_ (_SPI_CR1) |= BR_0;// pclk/4

2. Weka biti za CPOL na CPHA ili kufafanua uhusiano kati ya uhamisho wa data na muda wa mfululizo wa saa (ona mchoro kwenye ukurasa wa 240)

Kwa kuwa tunasoma hifadhidata hapa na hatuangalii miundo, hebu tuangalie kwa karibu maelezo ya maandishi ya biti za CPOL na CPHA kwenye ukurasa wa 704 (Maelezo ya Jumla ya SPI):

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Awamu ya saa na polarity
Kwa kutumia vipande vya CPOL na CPHA vya rejista ya SPI_CR1, unaweza kuchagua mahusiano manne ya muda kwa utaratibu. CPOL (mchanganyiko wa saa) hudhibiti hali ya mawimbi ya saa wakati hakuna data inayotumwa. Kidogo hiki kinadhibiti aina za bwana na mtumwa. CPOL ikiwekwa upya, pini ya SCK iko chini katika hali ya kupumzika. Biti ya CPOL ikiwekwa, pini ya SCK iko juu wakati wa hali ya kupumzika.
Biti ya CPHA (awamu ya saa) inapowekwa, kipigo cha juu cha mtego ni ukingo wa pili wa mawimbi ya SCK (inashuka ikiwa CPOL iko wazi, ikipanda CPOL ikiwa imewekwa). Data inachukuliwa na mabadiliko ya pili katika ishara ya saa. Ikiwa biti ya CPHA ni wazi, kipigo cha juu cha trap ni ukingo wa kupanda wa mawimbi ya SCK (makali yanayoanguka ikiwa CPOL imewekwa, ukingo wa kupanda ikiwa CPOL imeondolewa). Data inanaswa katika mabadiliko ya kwanza katika ishara ya saa.

Baada ya kunyonya ujuzi huu, tunafikia hitimisho kwamba bits zote mbili lazima zibaki zero, kwa sababu Tunataka mawimbi ya SCK ibaki ya chini wakati haitumiki, na data isambazwe kwenye ukingo unaoinuka wa mpigo (ona Mtini. Kupanda Edge Karatasi ya data ya DM634

Kwa njia, hapa tulikutana kwanza na kipengele cha msamiati katika hifadhidata za ST: ndani yao maneno "kuweka upya kidogo hadi sifuri" imeandikwa. kuweka upya kidogona sio kusafisha kidogo, kama, kwa mfano, Atmega.

3. Weka biti ya DFF ili kubaini ikiwa kizuizi cha data ni umbizo la biti 8 au 16

Nilichukua DM16 ya 634-bit ili nisijisumbue na kusambaza data ya 12-bit PWM, kama DM633. Inafahamika kuweka DFF kuwa moja:

#define DFF         0x0800

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

4. Sanidi biti ya LSBFIRST katika sajili ya SPI_CR1 ili kubainisha umbizo la kuzuia

LSBFIRST, kama jina lake linavyopendekeza, husanidi utumaji kwa uchache muhimu kwanza. Lakini DM634 inataka kupokea data kuanzia muhimu zaidi. Kwa hiyo, tunaiacha upya.

5. Katika hali ya maunzi, ikiwa pembejeo kutoka kwa pini ya NSS inahitajika, tumia ishara ya juu kwenye pini ya NSS wakati wa mlolongo mzima wa uhamisho wa byte. Katika hali ya programu ya NSS, weka biti za SSM na SSI kwenye rejista ya SPI_CR1. Ikiwa pini ya NSS itatumika kama matokeo, biti ya SSOE pekee ndiyo inayohitaji kuwekwa.

Sakinisha SSM na SSI ili kusahau kuhusu hali ya maunzi ya NSS:

#define SSI         0x0100
#define SSM         0x0200

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

6. Biti za MSTR na SPE lazima ziwekwe (zinasalia zimewekwa ikiwa tu ishara ya NSS iko juu)

Kwa kweli, kwa biti hizi tunateua SPI yetu kama bwana na kuiwasha:

#define MSTR        0x0004
#define SPE         0x0040

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

SPI imeundwa, hebu tuandike mara moja kazi zinazotuma byte kwa dereva. Endelea kusoma 25.3.3 "Kusanidi SPI katika hali kuu":

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Agizo la kuhamisha data
Usambazaji huanza wakati baiti inapoandikwa kwa bafa ya Tx.
Baiti ya data imepakiwa kwenye rejista ya mabadiliko katika sambamba mode (kutoka kwa basi ya ndani) wakati wa uhamisho wa bit ya kwanza, baada ya hapo hupitishwa kwa mfululizo Modi ya pin ya MOSI, mbele kidogo ya kwanza au ya mwisho kulingana na mpangilio wa biti ya LSBFIRST kwenye rejista ya CPI_CR1. Bendera ya TXE imewekwa baada ya usambazaji wa data kutoka Tx bafa hadi kuhama rejista, na pia hutoa usumbufu ikiwa biti ya TXEIE kwenye rejista ya CPI_CR1 imewekwa.

Niliangazia maneno machache katika tafsiri ili kuvutia kipengele kimoja cha utekelezaji wa SPI katika vidhibiti vya STM. Kwenye Atmega bendera ya TXE (Tx Tupu, Tx ni tupu na iko tayari kupokea data) huwekwa tu baada ya baiti nzima kutumwa nje. Na hapa bendera hii imewekwa baada ya byte kuingizwa kwenye rejista ya mabadiliko ya ndani. Kwa kuwa inasukumwa huko na bits zote kwa wakati mmoja (sambamba), na kisha data inahamishwa kwa mlolongo, TXE imewekwa kabla ya kutumwa kabisa. Hii ni muhimu kwa sababu kwa upande wa dereva wetu wa LED, tunahitaji kuvuta pini ya LAT baada ya kutuma Kila data, i.e. Bendera ya TXE pekee haitatutosha.

Hii ina maana kwamba tunahitaji bendera nyingine. Wacha tuangalie 25.3.7 - "Bendera za Hali":

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
<…>
Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
bendera ya BUSY
Bendera ya BSY imewekwa na kusafishwa na maunzi (kuiandikia haina athari). Bendera ya BSY inaonyesha hali ya safu ya mawasiliano ya SPI.
Inaweka upya:
uhamishaji unapokamilika (isipokuwa katika hali kuu ikiwa uhamishaji unaendelea)
wakati SPI imezimwa
wakati kosa la hali kuu linatokea (MODF=1)
Ikiwa uhamishaji hauendelezwi, alama ya BSY inafutwa kati ya kila uhamishaji wa data

Sawa, hii itakuja kwa manufaa. Hebu tujue ni wapi bafa ya Tx iko. Ili kufanya hivyo, soma "Daftari ya Data ya SPI":

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Bits 15:0 DR[15:0] Sajili ya Data
Data iliyopokelewa au data ya kutumwa.
Rejesta ya data imegawanywa katika vihifadhi viwili - moja ya kuandika (kusambaza bafa) na moja ya kusoma (pokea bafa). Kuandikia rejista ya data huandika kwa bafa ya Tx, na kusoma kutoka kwa rejista ya data kutarudisha thamani iliyo kwenye bafa ya Rx.

Kweli, na rejista ya hali, ambapo bendera za TXE na BSY zinapatikana:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Tunaandika:

#define _SPI_DR  0x0C
#define _SPI_SR  0x08

#define BSY         0x0080
#define TXE         0x0002

void dm_shift16(uint16_t value)
{
    _SPI2_(_SPI_DR) = value; //send 2 bytes
    while (!(_SPI2_(_SPI_SR) & TXE)); //wait until they're sent
}

Kweli, kwa kuwa tunahitaji kupitisha mara 16 ka mbili, kulingana na idadi ya matokeo ya dereva wa LED, kitu kama hiki:

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();
}

Lakini bado hatujui jinsi ya kuvuta pini ya LAT, kwa hivyo tutarudi kwa I/O.

Kuweka pini

Katika STM32F1, rejista zinazohusika na hali ya pini ni za kawaida kabisa. Ni wazi kwamba kuna zaidi yao kuliko Atmega, lakini pia ni tofauti na chips nyingine za STM. Sehemu ya 9.1 Maelezo ya Jumla ya GPIO:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Kila moja ya bandari za madhumuni ya jumla ya I/O (GPIO) ina rejista mbili za usanidi wa biti 32 (GPIOx_CRL na GPIOx_CRH), rejista mbili za data za biti 32 (GPIOx_IDR na GPIOx_ODR), rejista ya kuweka/kuweka upya 32-bit (GPIOx_BSRR), rejista ya kuweka upya 16-bit (GPIOx_BRR) na 32- rejista ya kuzuia kidogo (GPIOx_LCKR).

Daftari mbili za kwanza si za kawaida, na pia hazifai kabisa, kwa sababu pini 16 za bandari zimetawanyika juu yao katika muundo wa "bits nne kwa ndugu". Wale. pini sifuri hadi saba ziko katika CRL, na zilizosalia ziko katika CRH. Wakati huo huo, rejista zilizobaki zina mafanikio ya vipande vya pini zote za bandari - mara nyingi hubaki nusu "imehifadhiwa".

Kwa unyenyekevu, hebu tuanze kutoka mwisho wa orodha.

Hatuhitaji rejista ya kuzuia.

Rejista zilizowekwa na kuweka upya ni za kuchekesha sana kwa kuwa zinarudia kila mmoja: unaweza kuandika kila kitu kwenye BSRR tu, ambapo bits 16 za juu zitaweka upya pini hadi sifuri, na zile za chini zitawekwa 1, au unaweza pia. tumia BRR, biti 16 za chini ambazo weka upya pini pekee . Ninapenda chaguo la pili. Rejesta hizi ni muhimu kwa sababu hutoa ufikiaji wa atomiki kwa pini:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Weka Atomiki au Weka Upya
Hakuna haja ya kuzima ukatizaji wakati wa kutayarisha GPIOx_ODR katika kiwango kidogo: biti moja au zaidi zinaweza kubadilishwa kwa operesheni moja ya uandishi wa atomiki APB2. Hii inafanikiwa kwa kuandika "1" kwa rejista ya kuweka/kuweka upya (GPIOx_BSRR au, kwa kuweka upya tu, GPIOx_BRR) ya biti inayohitaji kubadilishwa. Biti zingine zitabaki bila kubadilika.

Daftari za data zina majina ya kujieleza kabisa - IDR = Pembejeo Daftari la Mwelekeo, rejista ya pembejeo; ODR = pato Daftari la Mwelekeo, rejista ya pato. Hatutazihitaji katika mradi wa sasa.

Na hatimaye, rejista za udhibiti. Kwa kuwa tunavutiwa na pini za pili za SPI, ambazo ni PB13, PB14 na PB15, mara moja tunaangalia CRH:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Na tunaona kwamba tutahitaji kuandika kitu katika bits kutoka 20 hadi 31.

Tayari tumegundua juu ya kile tunachotaka kutoka kwa pini, kwa hiyo hapa nitafanya bila skrini, nitasema tu kwamba MODE inabainisha mwelekeo (pembejeo ikiwa bits zote mbili zimewekwa kwa 0) na kasi ya pini (tunahitaji 50MHz, i.e. pini zote mbili hadi "1"), na CNF inaweka hali: mara kwa mara "sukuma-vuta" - 00, "mbadala" - 10. Kwa chaguo-msingi, kama tunavyoona hapo juu, pini zote zina biti ya tatu kutoka chini (CNF0), inawaweka katika hali pembejeo inayoelea.

Kwa kuwa ninapanga kufanya kitu kingine na chip hii, kwa unyenyekevu nimefafanua maadili yote yanayowezekana ya MODE na CNF kwa rejista za udhibiti wa chini na wa juu.

Kwa namna fulani hivi

#define CNF0_0 0x00000004
#define CNF0_1 0x00000008
#define CNF1_0 0x00000040
#define CNF1_1 0x00000080
#define CNF2_0 0x00000400
#define CNF2_1 0x00000800
#define CNF3_0 0x00004000
#define CNF3_1 0x00008000
#define CNF4_0 0x00040000
#define CNF4_1 0x00080000
#define CNF5_0 0x00400000
#define CNF5_1 0x00800000
#define CNF6_0 0x04000000
#define CNF6_1 0x08000000
#define CNF7_0 0x40000000
#define CNF7_1 0x80000000
#define CNF8_0 0x00000004
#define CNF8_1 0x00000008
#define CNF9_0 0x00000040
#define CNF9_1 0x00000080
#define CNF10_0 0x00000400
#define CNF10_1 0x00000800
#define CNF11_0 0x00004000
#define CNF11_1 0x00008000
#define CNF12_0 0x00040000
#define CNF12_1 0x00080000
#define CNF13_0 0x00400000
#define CNF13_1 0x00800000
#define CNF14_0 0x04000000
#define CNF14_1 0x08000000
#define CNF15_0 0x40000000
#define CNF15_1 0x80000000

#define MODE0_0 0x00000001
#define MODE0_1 0x00000002
#define MODE1_0 0x00000010
#define MODE1_1 0x00000020
#define MODE2_0 0x00000100
#define MODE2_1 0x00000200
#define MODE3_0 0x00001000
#define MODE3_1 0x00002000
#define MODE4_0 0x00010000
#define MODE4_1 0x00020000
#define MODE5_0 0x00100000
#define MODE5_1 0x00200000
#define MODE6_0 0x01000000
#define MODE6_1 0x02000000
#define MODE7_0 0x10000000
#define MODE7_1 0x20000000
#define MODE8_0 0x00000001
#define MODE8_1 0x00000002
#define MODE9_0 0x00000010
#define MODE9_1 0x00000020
#define MODE10_0 0x00000100
#define MODE10_1 0x00000200
#define MODE11_0 0x00001000
#define MODE11_1 0x00002000
#define MODE12_0 0x00010000
#define MODE12_1 0x00020000
#define MODE13_0 0x00100000
#define MODE13_1 0x00200000
#define MODE14_0 0x01000000
#define MODE14_1 0x02000000
#define MODE15_0 0x10000000
#define MODE15_1 0x20000000

Pini zetu ziko kwenye bandari B (anwani ya msingi - 0x40010C00), msimbo:

#define _PORTB_(mem_offset) (*(volatile uint32_t *)(0x40010C00 + (mem_offset)))

#define _BRR  0x14
#define _BSRR 0x10
#define _CRL  0x00
#define _CRH  0x04

//ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ стандартный SPI2: MOSI Π½Π° B15, CLK Π½Π° B13
//LAT ΠΏΡƒΡΡ‚ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π° Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠΌ MISO – B14

//ΠΎΡ‡ΠΈΡ‰Π°Π΅ΠΌ Π΄Π΅Ρ„ΠΎΠ»Ρ‚Π½Ρ‹ΠΉ Π±ΠΈΡ‚, ΠΎΠ½ Π½Π°ΠΌ Ρ‚ΠΎΡ‡Π½ΠΎ Π½Π΅ Π½ΡƒΠΆΠ΅Π½
_PORTB_ (_CRH) &= ~(CNF15_0 | CNF14_0 | CNF13_0 | CNF12_0);

//Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для MOSI ΠΈ SCK
_PORTB_ (_CRH) |= CNF15_1 | CNF13_1;

//50 ΠœΠ“Ρ†, MODE = 11
_PORTB_ (_CRH) |= MODE15_1 | MODE15_0 | MODE14_1 | MODE14_0 | MODE13_1 | MODE13_0;

Na, ipasavyo, unaweza kuandika ufafanuzi wa LAT, ambao utabadilishwa na rejista za BRR na BSRR:

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

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

(LAT_low kwa hali ya hewa, imekuwa hivyo kila wakati, iache ikae)

Sasa kila kitu ni nzuri, lakini haifanyi kazi. Kwa sababu hii ni STM32, huokoa umeme, ambayo inamaanisha unahitaji kuwezesha saa ya vifaa vya pembeni vinavyohitajika.

Washa saa

Saa, inayojulikana pia kama Saa, inawajibika kwa kuweka saa. Na tayari tunaweza kugundua kifupi cha RCC. Tunaitafuta katika nyaraka: hii ni Rudisha na Udhibiti wa Saa.

Kama ilivyosemwa hapo juu, kwa bahati nzuri, sehemu ngumu zaidi ya mada ya saa ilifanywa kwa ajili yetu na watu kutoka STM, ambayo tunawashukuru sana (kwa mara nyingine tena nitatoa kiungo kwa tovuti ya Di Halt, ili kuweka wazi jinsi inavyochanganya). Tunahitaji tu rejista zinazohusika na kuwezesha uwekaji saa wa pembeni (Rejista za Saa ya Pembeni Wezesha). Kwanza, wacha tupate anwani ya msingi ya RCC, iko mwanzoni kabisa mwa "Ramani ya Kumbukumbu":

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

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

Na kisha bonyeza kwenye kiunga ambacho unajaribu kupata kitu kwenye sahani, au, bora zaidi, pitia maelezo ya rejista za kuwezesha kutoka kwa sehemu kuhusu. wezesha rejista. Ambapo tutapata RCC_APB1ENR na RCC_APB2ENR:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Na wao, ipasavyo, vyenye bits ambayo ni pamoja na saa ya SPI2, IOPB (I/O Port B) na kazi mbadala (AFIO).

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

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

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

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

Nambari ya mwisho inaweza kupatikana hapa.

Ikiwa una fursa na hamu ya kufanya majaribio, basi unganisha DM634 kama hii: DAI hadi PB15, DCK hadi PB13, LAT hadi PB14. Tunawasha dereva kutoka kwa volts 5, usisahau kuunganisha misingi.

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

STM8 PWM

PWM kwenye STM8

Nilipokuwa nikipanga tu nakala hii, niliamua, kwa mfano, kujaribu kujua utendaji fulani wa chip isiyojulikana kwa kutumia hifadhidata tu, ili nisije nikapata fundi viatu bila buti. STM8 ilikuwa bora kwa jukumu hili: kwanza, nilikuwa na bodi kadhaa za Kichina na STM8S103, na pili, sio maarufu sana, na kwa hivyo jaribu la kusoma na kupata suluhisho kwenye mtandao linategemea ukosefu wa suluhisho hizi.

Chip pia ina karatasi ya data ΠΈ mwongozo wa kumbukumbu RM0016, kwa kwanza kuna pinout na anwani za rejista, kwa pili - kila kitu kingine. STM8 imepangwa katika C katika IDE mbaya Maendeleo ya Visual ya ST.

Saa na I/O

Kwa default, STM8 inafanya kazi kwa mzunguko wa 2 MHz, hii lazima irekebishwe mara moja.

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Saa ya HSI (Kasi ya Juu ya Ndani).
Ishara ya saa ya HSI inatokana na oscillator ya ndani ya 16 MHz RC na kigawanyiko kinachoweza kupangwa (1 hadi 8). Imewekwa katika rejista ya kigawanyaji cha saa (CLK_CKDVR).
Kumbuka: mwanzoni, oscillator ya HSI RC yenye kigawanyiko cha 8 huchaguliwa kama chanzo kikuu cha ishara ya saa.

Tunapata anwani ya rejista kwenye hifadhidata, maelezo katika refman na kuona kwamba rejista inahitaji kufutwa:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Kwa kuwa tutaendesha PWM na kuunganisha LEDs, hebu tuangalie pinout:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Chip ni ndogo, kazi nyingi zimesimamishwa kwenye pini sawa. Kilicho kwenye mabano ya mraba ni "utendaji mbadala", inabadilishwa na "baiti chaguo" (chaguo ka) - kitu kama fuse za Atmega. Unaweza kubadilisha maadili yao kwa utaratibu, lakini sio lazima, kwa sababu Utendaji mpya huwashwa tu baada ya kuwasha upya. Ni rahisi kutumia ST Visual Programmer (iliyopakuliwa na Visual Develop), ambayo inaweza kubadilisha baiti hizi. Pinout inaonyesha kuwa pini za CH1 na CH2 za timer ya kwanza zimefichwa kwenye mabano ya mraba; ni muhimu kuweka bits AFR1 na AFR0 katika STVP, na ya pili pia itahamisha pato la CH1 la timer ya pili kutoka PD4 hadi PC5.

Kwa hivyo, pini 6 zitadhibiti LEDs: PC6, PC7 na PC3 kwa timer ya kwanza, PC5, PD3 na PA3 kwa pili.

Kuweka pini za I/O zenyewe kwenye STM8 ni rahisi na mantiki zaidi kuliko kwenye STM32:

  • inayojulikana kutoka kwa rejista ya mwelekeo wa data ya Atmega DDR (Daftari la Mielekeo ya Data): 1 = pato;
  • rejista ya kwanza ya udhibiti CR1, wakati pato, huweka hali ya kushinikiza-kuvuta (1) au kukimbia wazi (0); kwa kuwa ninaunganisha LED kwenye chip na cathodes, ninaacha zero hapa;
  • rejista ya pili ya udhibiti CR2, wakati pato, huweka kasi ya saa: 1 = 10 MHz

#define PA_DDR     *(volatile uint8_t *)0x005002
#define PA_CR2     *(volatile uint8_t *)0x005004
#define PD_DDR     *(volatile uint8_t *)0x005011
#define PD_CR2     *(volatile uint8_t *)0x005013
#define PC_DDR     *(volatile uint8_t *)0x00500C
#define PC_CR2     *(volatile uint8_t *)0x00500E

PA_DDR = (1<<3); //output
PA_CR2 |= (1<<3); //fast
PD_DDR = (1<<3); //output
PD_CR2 |= (1<<3); //fast
PC_DDR = ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //output
PC_CR2 |= ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //fast

Mpangilio wa PWM

Kwanza, hebu tufafanue masharti:

  • Mzunguko wa PWM - frequency ambayo kipima saa kinajibu;
  • Pakia upya kiotomatiki, AR - thamani ya kupakia kiotomatiki ambayo kipima saa kitahesabu (kipindi cha mapigo);
  • Sasisha Tukio, UEV - tukio ambalo hutokea wakati kipima muda kimehesabiwa hadi AR;
  • Mzunguko wa Wajibu wa PWM - Mzunguko wa wajibu wa PWM, mara nyingi huitwa "sababu ya wajibu";
  • Nasa/Linganisha Thamani - thamani ya kunasa/kulinganisha, ambayo kipima muda kimehesabiwa atafanya kitu (katika kesi ya PWM, inabadilisha ishara ya pato);
  • Thamani ya Kupakia mapema - thamani iliyopakiwa awali. Linganisha thamani haiwezi kubadilika wakati kipima saa kinaashiria, vinginevyo mzunguko wa PWM utavunjika. Kwa hivyo, maadili mapya yanayopitishwa huwekwa kwenye buffer na kutolewa nje wakati kipima saa kinafika mwisho wa siku iliyosalia na kuwekwa upya;
  • Imepangiliwa kingo ΠΈ Njia zilizopangwa katikati - alignment kando ya mpaka na katikati, sawa na Atmel PWM haraka ΠΈ Awamu-sahihi PWM.
  • OCiREF, Alama ya Marejeleo ya Pato la Kulinganisha - ishara ya pato la kumbukumbu, kwa kweli, kile kinachoonekana kwenye pini inayofanana katika hali ya PWM.

Kama inavyoonekana tayari kutoka kwa pinout, vipima muda viwili vina uwezo wa PWM - ya kwanza na ya pili. Zote mbili ni 16-bit, ya kwanza ina sifa nyingi za ziada (haswa, inaweza kuhesabu wote juu na chini). Tunahitaji wote wawili kufanya kazi kwa usawa, kwa hivyo niliamua kuanza na ile ya pili ambayo ni mbaya zaidi, ili nisitumie kwa bahati mbaya kitu ambacho hakipo. Shida fulani ni kwamba maelezo ya utendakazi wa PWM ya vipima muda katika mwongozo wa marejeleo yako katika sura kuhusu kipima saa cha kwanza (Njia ya PWM 17.5.7), kwa hivyo inabidi uruke huku na huko katika hati wakati wote.

PWM kwenye STM8 ina faida muhimu zaidi ya PWM kwenye Atmega:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
PWM Iliyopangwa Mipaka
Usanidi wa akaunti kutoka chini hadi juu
Kuhesabu kutoka chini kwenda juu kunatumika ikiwa biti ya DIR katika sajili ya TIM_CR1 itafutwa
Mfano
Mfano hutumia hali ya kwanza ya PWM. OCiREF ya marejeleo ya mawimbi ya PWM imeshikiliwa juu kwa muda mrefu kama TIM1_CNT < TIM1_CCRi. Vinginevyo inachukua kiwango cha chini. Ikiwa thamani ya kulinganisha katika rejista ya TIM1_CCRi ni kubwa kuliko thamani ya upakiaji kiotomatiki (rejista ya TIM1_ARR), mawimbi ya OCiREF hushikiliwa saa 1. Ikiwa thamani ya kulinganisha ni 0, OCiREF inashikiliwa kwa sifuri....

Kipima muda cha STM8 wakati sasisha tukio hundi kwanza kulinganisha thamani, na kisha tu hutoa ishara ya kumbukumbu. Kipima saa cha Atmega kwanza husonga na kisha kulinganisha, na kusababisha compare value == 0 pato ni sindano, ambayo lazima ishughulikiwe kwa namna fulani (kwa mfano, kwa kugeuza mantiki kwa utaratibu).

Kwa hivyo kile tunachotaka kufanya: 8-bit PWM (AR == 255), kuhesabu kutoka chini hadi juu, alignment kando ya mpaka. Kwa kuwa balbu za mwanga zimeunganishwa kwenye chip na cathode, PWM inapaswa kutoa 0 (LED) hadi kulinganisha thamani na 1 baada.

Tayari tumesoma kuhusu baadhi Njia ya PWM, kwa hivyo tunapata rejista inayohitajika ya kipima saa cha pili kwa kutafuta katika mwongozo wa marejeleo kwa kifungu hiki (18.6.8 - TIMx_CCMR1):

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
110: Hali ya kwanza ya PWM – unapohesabu kutoka chini hadi juu, chaneli ya kwanza inafanya kazi huku TIMx_CNT <TIMx_CCR1. Vinginevyo, kituo cha kwanza hakitumiki. [zaidi katika hati kuna kunakili-ubandike kwa makosa kutoka kwa kipima muda 1] 111: Hali ya pili ya PWM - unapohesabu kutoka chini hadi juu, chaneli ya kwanza haitumiki huku TIMx_CNT < TIMx_CCR1. Vinginevyo, kituo cha kwanza kinatumika.

Kwa kuwa LED zimeunganishwa na MK na cathodes, hali ya pili inafaa kwetu (ya kwanza pia, lakini hatujui hilo bado).

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Bit 3 OC1PE: Washa pini 1 ya upakiaji mapema
0: Sajili ya kupakia mapema kwenye TIMx_CCR1 imezimwa. Unaweza kuandika kwa TIMx_CCR1 wakati wowote. Thamani mpya inafanya kazi mara moja.
1: Rejista ya upakiaji mapema kwenye TIMx_CCR1 imewashwa. Shughuli za kusoma/kuandika fikia rejista ya upakiaji mapema. Thamani iliyopakiwa awali TIMx_CCR1 inapakiwa kwenye rejista ya kivuli wakati wa kila tukio la sasisho.
*Kumbuka: Ili hali ya PWM ifanye kazi vizuri, rejista za upakiaji mapema lazima ziwashwe. Hii si lazima katika hali ya mawimbi moja (biti ya OPM imewekwa kwenye rejista ya TIMx_CR1).

Sawa, wacha tuwashe kila kitu tunachohitaji kwa chaneli tatu za kipima saa cha pili:

#define TIM2_CCMR1 *(volatile uint8_t *)0x005307
#define TIM2_CCMR2 *(volatile uint8_t *)0x005308
#define TIM2_CCMR3 *(volatile uint8_t *)0x005309

#define PWM_MODE2   0x70 //PWM mode 2, 0b01110000
#define OCxPE       0x08 //preload enable

TIM2_CCMR1 = (PWM_MODE2 | OCxPE);
TIM2_CCMR2 = (PWM_MODE2 | OCxPE);
TIM2_CCMR3 = (PWM_MODE2 | OCxPE);

AR ina rejista mbili-bit nane, kila kitu ni rahisi:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Timer ya pili inaweza tu kuhesabu kutoka chini hadi juu, alignment kando ya mpaka, hakuna kitu kinachohitaji kubadilishwa. Hebu tuweke kigawanyiko cha mzunguko, kwa mfano, hadi 256. Kwa timer ya pili, mgawanyiko umewekwa kwenye rejista ya TIM2_PSCR na ni nguvu ya mbili:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Kinachobaki ni kuwasha hitimisho na timer ya pili yenyewe. Tatizo la kwanza linatatuliwa na rejista Nasa/Linganisha Kuwawezesha: kuna njia mbili, tatu zilizotawanyika kwa usawa. Hapa tunaweza pia kujifunza kwamba inawezekana kubadili polarity ya ishara, i.e. kimsingi, iliwezekana kutumia Njia ya PWM 1. Tunaandika:

#define TIM2_CCER1 *(volatile uint8_t *)0x00530A
#define TIM2_CCER2 *(volatile uint8_t *)0x00530B

#define CC1E  (1<<0) // CCER1
#define CC2E  (1<<4) // CCER1
#define CC3E  (1<<0) // CCER2

TIM2_CCER1 = (CC1E | CC2E);
TIM2_CCER2 = CC3E;

Na mwishowe, tunaanza kipima saa kwenye rejista ya TIMx_CR1:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Wacha tuandike analog rahisi ya AnalogWrite(), ambayo itahamisha maadili halisi kwa kipima saa kwa kulinganisha. Rejesta zimetajwa kwa kutabirika Nasa/Linganisha rejista, kuna mbili kati ya hizo kwa kila kituo: biti 8 za mpangilio wa chini katika TIM2_CCRxL na zile za mpangilio wa juu katika TIM2_CCRxH. Kwa kuwa tumeunda PWM ya 8-bit, inatosha kuandika sehemu ndogo tu muhimu:

#define TIM2_CCR1L *(volatile uint8_t *)0x005312
#define TIM2_CCR2L *(volatile uint8_t *)0x005314
#define TIM2_CCR3L *(volatile uint8_t *)0x005316

void setRGBled(uint8_t r, uint8_t g, uint8_t b)
{
    TIM2_CCR1L = r;
    TIM2_CCR2L = g;
    TIM2_CCR3L = b;
}

Msomaji makini ataona kwamba tuna PWM yenye kasoro kidogo, haiwezi kuzalisha 100% ya kujaza (kwa thamani ya juu ya 255, ishara inageuzwa kwa mzunguko mmoja wa timer). Kwa LEDs hii haijalishi, na msomaji makini anaweza tayari nadhani jinsi ya kurekebisha.

PWM kwenye kipima saa cha pili inafanya kazi, wacha tuendelee hadi ya kwanza.

Timer ya kwanza ina bits sawa katika rejista sawa (ni kwamba bits hizo ambazo zilibaki "zimehifadhiwa" katika timer ya pili hutumiwa kikamilifu katika kwanza kwa kila aina ya mambo ya juu). Kwa hivyo, inatosha kupata anwani za rejista sawa kwenye daftari na kunakili nambari. Kweli, badilisha thamani ya kigawanyaji cha masafa, kwa sababu... kipima saa cha kwanza kinataka kupokea si nguvu ya mbili, lakini thamani halisi ya 16-bit katika rejista mbili Prescaler Juu ΠΈ Chini. Tunafanya kila kitu na ... timer ya kwanza haifanyi kazi. Kuna nini?

Tatizo linaweza kutatuliwa tu kwa kuangalia kupitia sehemu nzima kuhusu rejista za udhibiti wa timer 1, ambapo tunatafuta moja ambayo timer ya pili haina. Kutakuwa na 17.7.30 Rejesta ya mapumziko (TIM1_BKR), ambapo kuna sehemu hii:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Washa pato kuu

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Hayo ni yote kwa uhakika sasa, kanuni hapo.

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

STM8 Multiplex

Kuzidisha kwa STM8

Mradi wa tatu wa mini ni kuunganisha LED nane za RGB kwa kipima saa cha pili katika hali ya PWM na kuzifanya zionyeshe rangi tofauti. Inategemea wazo la kuzidisha kwa LED, ambayo ni kwamba ikiwa unawasha na kuzima LEDs haraka sana, itaonekana kwetu kuwa zinawashwa kila wakati (kuendelea kwa maono, hali ya mtazamo wa kuona). Niliwahi kufanya hivyo kitu kama hiki kwenye Arduino.

Algorithm ya kazi inaonekana kama hii:

  • iliunganisha anode ya LED ya kwanza ya RGB;
  • kuiwasha, kutuma ishara muhimu kwa cathodes;
  • kusubiri hadi mwisho wa mzunguko wa PWM;
  • iliunganisha anode ya LED ya pili ya RGB;
  • iwashe...

Naam, nk. Bila shaka, kwa operesheni nzuri inahitajika kwamba anode imeunganishwa na LED "inawaka" kwa wakati mmoja. Naam, au karibu. Kwa hali yoyote, tunahitaji kuandika msimbo ambao utatoa maadili katika njia tatu za timer ya pili, kuzibadilisha wakati UEV itafikiwa, na wakati huo huo ubadilishe RGB LED inayotumika sasa.

Kwa kuwa ubadilishaji wa LED ni otomatiki, tunahitaji kuunda "kumbukumbu ya video" ambayo kidhibiti cha kukatiza kitapokea data. Hii ni safu rahisi:

uint8_t colors[8][3];

Ili kubadilisha rangi ya LED maalum, itakuwa ya kutosha kuandika maadili yanayotakiwa katika safu hii. Na kutofautisha kutakuwa na jukumu la nambari ya LED inayofanya kazi

uint8_t cnt;

Demux

Kwa kuzidisha vizuri, tunahitaji, isiyo ya kawaida, CD74HC238 demultiplexer. Demultiplexer - chip inayotekelezea mwendeshaji katika maunzi <<. Kupitia pini tatu za pembejeo (bits 0, 1 na 2) tunalisha nambari ya bit-tatu X, na kwa kujibu inawasha nambari ya pato (1<<X) Pembejeo zilizobaki za chip hutumiwa kuongeza muundo mzima. Tunahitaji chip hii sio tu kupunguza idadi ya pini zilizochukuliwa za microcontroller, lakini pia kwa usalama - ili si kwa ajali kuwasha LED zaidi kuliko iwezekanavyo na si kuchoma MK. Chip inagharimu senti na inapaswa kuwekwa kila wakati kwenye baraza la mawaziri la dawa la nyumbani.

CD74HC238 yetu itakuwa na jukumu la kusambaza voltage kwenye anode ya LED inayotaka. Katika multiplex iliyojaa kamili, ingesambaza voltage kwenye safu kupitia P-MOSFET, lakini katika onyesho hili inawezekana moja kwa moja, kwa sababu. huchota 20 mA, kulingana na makadirio ya juu kabisa katika hifadhidata. Kutoka Karatasi ya data ya CD74HC238 tunahitaji pinouts na karatasi hii ya kudanganya:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
H = kiwango cha juu cha voltage, L = kiwango cha chini cha voltage, X - usijali

Tunaunganisha E2 na E1 chini, E3, A0, A1 na A3 ili kubandika PD5, PC3, PC4 na PC5 ya STM8. Kwa kuwa jedwali lililo hapo juu lina viwango vya chini na vya juu, tunasanidi pini hizi kama pini za kusukuma-kuvuta.

PWM

PWM kwenye kipima saa cha pili imesanidiwa kwa njia sawa na katika hadithi iliyopita, na tofauti mbili:

Kwanza, tunahitaji kuwezesha usumbufu Sasisha Tukio (UEV) ambayo itaita kitendakazi ambacho hugeuza LED inayotumika. Hii inafanywa kwa kubadilisha kidogo Sasisha Ukatiza Wezesha katika rejista yenye jina la kuwaambia

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
Kataza kuwezesha rejista

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Tofauti ya pili inahusiana na uzushi wa kuzidisha, kama vile ghosting - mwanga wa vimelea wa diode. Kwa upande wetu, inaweza kuonekana kutokana na ukweli kwamba timer, baada ya kusababisha usumbufu kwenye UEV, inaendelea kuashiria, na mtoaji wa usumbufu hana muda wa kubadili LED kabla ya timer kuanza kuandika kitu kwa pini. Ili kupambana na hili, itabidi ugeuze mantiki (0 = mwangaza wa juu zaidi, 255 = hakuna kitu kilichowashwa) na epuka maadili ya mzunguko wa wajibu uliokithiri. Wale. hakikisha kuwa baada ya UEV LED zinazima kabisa kwa mzunguko mmoja wa PWM.

Kubadilisha polarity:

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

Epuka kuweka r, g na b hadi 255 na kumbuka kuzigeuza unapozitumia.

Inakatiza

Kiini cha kukatiza ni kwamba chini ya hali fulani chip huacha kutekeleza programu kuu na kuita kazi fulani ya nje. Vikwazo hutokea kutokana na mvuto wa nje au wa ndani, ikiwa ni pamoja na kipima muda.

Tulipounda mradi kwa mara ya kwanza katika ST Visual Develop, pamoja na main.c tulipokea dirisha na faili ya ajabu stm8_interrupt_vector.c, imejumuishwa kiotomatiki kwenye mradi. Katika faili hii, chaguo la kukokotoa limepewa kila usumbufu NonHandledInterrupt. Tunahitaji kufunga utendaji wetu kwa ukatizaji unaotaka.

Hifadhidata ina jedwali la viveta vya kukatiza, ambapo tunapata zile tunazohitaji:

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8
13 TIM2 sasisho/furika
14 TIM2 kukamata/kulinganisha

Tunahitaji kubadilisha LED kwenye UEV, kwa hivyo tunahitaji kukatiza #13.

Ipasavyo, kwanza, katika faili stm8_interrupt_vector.c badilisha jina chaguo-msingi la kitendakazi kinachohusika na kukatiza Nambari 13 (IRQ13) kuwa lako mwenyewe:

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

Pili, tutalazimika kuunda faili main.h na maudhui yafuatayo:

#ifndef __MAIN_H
#define __MAIN_H

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

Na hatimaye, andika kazi hii katika yako 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;
}

Kilichobaki ni kuwezesha kukatizwa. Hii inafanywa kwa kutumia amri ya mkusanyiko rim - itabidi utafute ndani Mwongozo wa Programu:

//enable interrupts
_asm("rim");

Amri nyingine ya mkusanyiko ni sim - huzima vikatizo. Lazima zizimwe wakati maadili mapya yanaandikwa kwa "kumbukumbu ya video", ili usumbufu unaosababishwa na wakati mbaya usiharibu safu.

Kanuni zote - kwenye GitHub.

Soma hifadhidata 2: SPI kwenye STM32; PWM, vipima muda na kukatizwa kwenye STM8

Ikiwa angalau mtu anaona makala hii kuwa muhimu, basi sikuiandika bure. Nitafurahi kupokea maoni na maoni, nitajaribu kujibu kila kitu.

Chanzo: mapenzi.com

Kuongeza maoni