Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

В birinchi qism Men Arduino shimlaridan o'sgan hobbi elektronika muhandislariga mikrokontrollerlar uchun ma'lumotlar jadvallari va boshqa hujjatlarni qanday va nima uchun o'qishlari kerakligini aytishga harakat qildim. Matn katta bo'lib chiqdi, shuning uchun men amaliy misollarni alohida maqolada ko'rsatishga va'da berdim. Xo'sh, u o'zini sut qo'ziqorini deb atagan ...

Bugun men sizga juda oddiy, ammo ko'plab loyihalar uchun zarur bo'lgan STM32 (Blue Pill) va STM8 kontrollerlaridagi vazifalarni hal qilish uchun ma'lumotlar jadvallaridan qanday foydalanishni ko'rsataman. Barcha demo-loyihalar mening sevimli LED-larimga bag'ishlangan, biz ularni ko'p miqdorda yoritamiz, buning uchun har xil qiziqarli tashqi qurilmalardan foydalanishimiz kerak bo'ladi.

Matn yana katta bo'lib chiqdi, shuning uchun men qulaylik uchun tarkibni yarataman:

STM32 Blue Pill: DM16 drayveri bilan 634 LED
STM8: Oltita PWM pinini sozlash
STM8: uchta pinda 8 ta RGB LED, uzilishlar

Rad etish: Men muhandis emasman, men elektronikada chuqur bilimga egaman deb da'vo qilmayman, maqola men kabi havaskorlar uchun mo'ljallangan. Darhaqiqat, men ikki yil oldin o'zimni maqsadli auditoriya deb hisoblaganman. Agar kimdir menga notanish chipdagi ma'lumotlar varaqlarini o'qish qo'rqinchli emasligini aytganida edi, men Internetda ba'zi kod qismlarini qidirishga va qaychi va yopishqoq lenta bilan tayoqchalarni ixtiro qilishga ko'p vaqt sarflamagan bo'lardim.

Ushbu maqolada asosiy e'tibor loyihalarga emas, balki ma'lumotlar jadvallariga qaratilgan, shuning uchun kod juda toza va ko'pincha tor bo'lmasligi mumkin. Loyihalarning o'zi juda oddiy, garchi yangi chip bilan birinchi tanishish uchun mos bo'lsa ham.

Umid qilamanki, mening maqolam kimgadir sevimli mashg'ulotiga botishning xuddi shunday bosqichida yordam beradi.

STM32

DM16 va SPI bilan 634 ta LED

Blue Pill (STM32F103C8T6) va DM634 LED drayverini ishlatadigan kichik loyiha. Ma'lumotlar jadvallaridan foydalanib, biz drayverni, STM IO portlarini aniqlaymiz va SPI ni sozlaymiz.

DM634

16 ta 16-bitli PWM chiqishiga ega Tayvan chipi zanjirlarda ulanishi mumkin. Past darajadagi 12-bitli model mahalliy loyihadan ma'lum Lightpack. Bir vaqtlar, DM63x va taniqli TLC5940 o'rtasida tanlov qilib, men bir necha sabablarga ko'ra DM ni tanladim: 1) Aliexpress-dagi TLC, albatta, soxta, ammo bu emas; 2) DM o'z chastota generatoriga ega avtonom PWMga ega; 3) Alidan posilka kutmasdan, uni Moskvada arzonga sotib olish mumkin edi. Va, albatta, tayyor kutubxonadan foydalanishdan ko'ra, chipni o'zingiz boshqarishni o'rganish qiziq edi. Chiplar endi asosan SSOP24 to'plamida taqdim etiladi, ularni adapterga lehimlash oson.

Ishlab chiqaruvchi Tayvanlik bo'lgani uchun, tafsilotli ro'yxat chip xitoy ingliz tilida yozilgan, bu qiziqarli bo'lishini anglatadi. Avval biz pinoutga qaraymiz (Pin ulanishi) qaysi oyoqni nimaga ulash kerakligini va pinlarning tavsifi (Pin tavsifi). 16 pin:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
DC lavabo manbalari (ochiq drenaj)

Sink / Ochiq drenajli chiqish - drenaj; kiruvchi oqim manbai; chiqish faol holatda erga ulangan - LEDlar haydovchiga katodlar orqali ulangan. Elektr jihatdan, bu, albatta, "ochiq drenaj" emas (ochiq drenaj), lekin ma'lumotlar varaqlarida drenaj rejimidagi pinlar uchun bu belgi ko'pincha topiladi.

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Chiqish oqimi qiymatini o'rnatish uchun REXT va GND o'rtasidagi tashqi rezistorlar

REXT pin va tuproq o'rtasida chiqishlarning ichki qarshiligini nazorat qiluvchi mos yozuvlar rezistor o'rnatilgan, ma'lumotlar varaqining 9-betidagi grafikga qarang. DM634 da bu qarshilik umumiy yorqinlikni o'rnatib, dasturiy ta'minot orqali ham boshqarilishi mumkin (global yorqinlik); Men ushbu maqolada tafsilotlarga kirmayman, men bu erda 2.2 - 3 kOhm qarshilik qo'yaman.

Chipni qanday boshqarishni tushunish uchun qurilma interfeysi tavsifini ko'rib chiqaylik:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Ha, mana bu, butun shon-shuhrat bilan Xitoy ingliz tili. Buni tarjima qilish muammoli, agar xohlasangiz, buni tushunishingiz mumkin, ammo boshqa yo'l bor - funktsional o'xshash TLC5940 ga ulanish ma'lumotlar jadvalida qanday tasvirlanganiga qarang:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
... Qurilmaga ma'lumotlarni kiritish uchun faqat uchta pin kerak. SCLK signalining ko'tarilgan qirrasi ma'lumotlarni SIN pinidan ichki registrga o'tkazadi. Barcha ma'lumotlar yuklangandan so'ng, qisqa yuqori XLAT signali ketma-ket uzatilgan ma'lumotlarni ichki registrlarga mahkamlaydi. Ichki registrlar XLAT signal darajasi tomonidan ishga tushiriladigan eshiklardir. Barcha ma'lumotlar birinchi navbatda eng muhim bit uzatiladi.

Latch – mandal/latch/qulf.
Ko'tarilgan chekka - pulsning oldingi qirrasi
Avval MSB – eng muhim (eng chap) bir oz oldinga.
soat ma'lumotlari uchun – ma’lumotlarni ketma-ket (bitma-bit) uzatish.

So'z mandal ko'pincha chiplar uchun hujjatlarda uchraydi va turli yo'llar bilan tarjima qilinadi, shuning uchun tushunish uchun men o'zimga ruxsat beraman

kichik ta'lim dasturiLED drayveri asosan siljish registridir. "Shift" (smena) nomida - qurilma ichidagi ma'lumotlarning bit bo'yicha harakati: ichkariga kiritilgan har bir yangi bit butun zanjirni oldinga siljiydi. Shift paytida hech kim LEDlarning xaotik miltillashini kuzatishni istamaganligi sababli, jarayon ishchi registrlardan damper bilan ajratilgan bufer registrlarida sodir bo'ladi (mandal) - bitlar kerakli ketma-ketlikda joylashtirilgan kutish xonasining bir turi. Har bir narsa tayyor bo'lgach, deklanşör ochiladi va bitlar oldingi partiyani almashtirib, ishga kirishadi. So'z mandal mikrosxemalar uchun hujjatlarda deyarli har doim bunday damperni nazarda tutadi, u qanday kombinatsiyalarda ishlatilishidan qat'i nazar.

Shunday qilib, DM634 ga ma'lumotlarni uzatish quyidagicha amalga oshiriladi: DAI kiritishini uzoq LEDning eng muhim bitining qiymatiga o'rnating, DCK ni yuqoriga va pastga torting; DAI kiritishni keyingi bitning qiymatiga o'rnating, DCK ni torting; va hokazo barcha bitlar uzatilgunga qadar (soatiga kirdi), shundan so'ng biz LATni tortamiz. Buni qo'lda qilish mumkin (bit portlash), lekin buning uchun maxsus mo'ljallangan SPI interfeysidan foydalanish yaxshiroqdir, chunki u bizning STM32-da ikki nusxada taqdim etilgan.

Moviy tabletka STM32F103

Kirish: STM32 kontrollerlari qo'rqinchli tuyulishi mumkin bo'lganidan ko'ra Atmega328 ga qaraganda ancha murakkab. Bundan tashqari, energiyani tejash uchun deyarli barcha tashqi qurilmalar ishga tushirilganda o'chiriladi va soat chastotasi ichki manbadan 8 MGts ni tashkil qiladi. Yaxshiyamki, STM dasturchilari chipni "hisoblangan" 72 MGts ga yetkazadigan kodni yozishdi va men bilgan barcha IDE mualliflari uni ishga tushirish protsedurasiga kiritdilar, shuning uchun biz soatni hisoblashimiz shart emas (lekin). agar chindan ham xohlasangiz qila olasiz). Ammo siz tashqi qurilmalarni yoqishingiz kerak bo'ladi.

Hujjatlar: Blue Pill mashhur STM32F103C8T6 chipi bilan jihozlangan, buning uchun ikkita foydali hujjat mavjud:

Ma'lumotlar jadvalida bizni qiziqtirishi mumkin:

  • Pinouts - chip pinouts - agar biz taxtalarni o'zimiz qilishga qaror qilsak;
  • Xotira xaritasi - ma'lum bir chip uchun xotira xaritasi. Yo'l-yo'riq qo'llanmada butun chiziq uchun xarita mavjud va unda bizda mavjud bo'lmagan registrlar haqida so'z boradi.
  • Pin ta'riflari jadvali - pinlarning asosiy va muqobil funktsiyalari ro'yxati; "ko'k hap" uchun siz pinlar va ularning funktsiyalari ro'yxati bilan Internetda qulayroq rasmlarni topishingiz mumkin. Shuning uchun, biz darhol Google Blue Pill pinoutini qidiramiz va ushbu rasmni qo'lda ushlab turamiz:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Eslatma: Internetdan olingan rasmda xatolik yuz berdi, bu izohlarda qayd etilgan, buning uchun rahmat. Rasm almashtirildi, ammo bu saboq - ma'lumotlarni ma'lumotlar jadvallaridan emas, balki tekshirish yaxshiroqdir.

Biz ma'lumotlar varag'ini olib tashlaymiz, Ma'lumotnomani ochamiz va bundan buyon biz faqat undan foydalanamiz.
Protsedura: biz standart kiritish/chiqarish bilan shug'ullanamiz, SPI ni sozlaymiz, kerakli tashqi qurilmalarni yoqamiz.

Kirish Chiqish

Atmega328-da I/U juda sodda tarzda amalga oshiriladi, shuning uchun STM32 opsiyalarining ko'pligi chalkash bo'lishi mumkin. Endi bizga faqat xulosalar kerak, ammo ularda ham to'rtta variant bor:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
ochiq drenaj, surish-tortish, muqobil surish, muqobil ochiq drenaj

"Tortish-surish" (surish) Arduino-ning odatiy chiqishi bo'lib, pin YUQORI yoki LOW qiymatini olishi mumkin. Ammo "ochiq drenaj" bilan bor qiyinchiliklar, garchi aslida bu erda hamma narsa oddiy:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Chiqish konfiguratsiyasi / port chiqishga tayinlanganda: / chiqish buferi yoqilgan: / – ochiq drenaj rejimi: chiqish registridagi “0” N-MOSni yoqadi, chiqish registridagi “1” portni Hi-Z rejimida qoldiradi ( P-MOS faollashtirilmagan ) / – push-pull rejimi: chiqish registridagi “0” N-MOSni, chiqish registridagi “1” esa P-MOSni faollashtiradi.

Ochiq drenaj o'rtasidagi barcha farq (ochiq drenaj) "surish-tortish" dan (surish) birinchi pinda YUQORI holatni qabul qila olmaydi: chiqish registriga bittasini yozishda u yuqori qarshilik rejimiga o'tadi (yuqori impedans, Salom). Nolni yozishda pin ikkala rejimda ham mantiqiy, ham elektr jihatdan bir xil harakat qiladi.

Oddiy chiqish rejimida pin oddiygina chiqish registrining mazmunini uzatadi. "Muqobil" da u mos keladigan tashqi qurilmalar tomonidan boshqariladi (9.1.4 ga qarang):

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Agar port biti muqobil funktsiya pin sifatida sozlangan bo'lsa, pin registri o'chiriladi va pin periferik pinga ulanadi.

Har bir pinning muqobil funksionalligi maqolada tasvirlangan PIN-kod ta'riflari Ma'lumotlar jadvali yuklab olingan rasmda. Agar pin bir nechta muqobil funktsiyalarga ega bo'lsa, nima qilish kerakligi haqidagi savolga javob ma'lumotlar varag'idagi izoh bilan beriladi:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Agar bir nechta tashqi qurilmalar bir xil pindan foydalansa, muqobil funksiyalar o'rtasidagi ziddiyatga yo'l qo'ymaslik uchun bir vaqtning o'zida faqat bitta periferik qurilmadan foydalanish kerak, periferik soatni yoqish biti (tegishli RCC registrida) yordamida almashtiriladi.

Nihoyat, chiqish rejimidagi pinlar ham soat tezligiga ega. Bu energiyani tejashning yana bir xususiyati; bizning holatlarimizda biz uni maksimal darajaga qo'yamiz va uni unutamiz.

Shunday qilib: biz SPI dan foydalanmoqdamiz, ya'ni ikkita pin (ma'lumotlar va soat signali bilan) "muqobil push-pull funktsiyasi" bo'lishi kerak va boshqasi (LAT) "muntazam surish" bo'lishi kerak. Ammo ularni tayinlashdan oldin, keling, SPI bilan shug'ullanamiz.

SPI

Yana bir kichik ta'lim dasturi

SPI yoki Serial Peripheral Interface (seriyali periferik interfeys) MKni boshqa MKlar va umuman tashqi dunyo bilan ulash uchun oddiy va juda samarali interfeysdir. Uning ishlash printsipi allaqachon yuqorida tavsiflangan, bu erda Xitoyning LED drayveri haqida (ma'lumotnoma qo'llanmasida, 25-bo'limga qarang). SPI master ("master") va qul ("qul") rejimida ishlashi mumkin. SPI to'rtta asosiy kanalga ega bo'lib, ulardan hammasi ham ishlatilmaydi:

  • MOSI, Master Output / Slave Input: bu pin ma'lumotlarni asosiy rejimda uzatadi va ma'lumotlarni tobe rejimda qabul qiladi;
  • MISO, Master Input / Slave Output: aksincha, u xo'jayinda qabul qiladi va qulda uzatadi;
  • SCK, Serial Clock: masterda ma'lumotlarni uzatish chastotasini o'rnatadi yoki qulda soat signalini oladi. Asosan zarba zarbalari;
  • SS, Slave Select: ushbu kanal yordamida qul undan nimadir talab qilinayotganini biladi. STM32 da u NSS deb ataladi, bu erda N = salbiy, ya'ni. agar bu kanalda tuproq mavjud bo'lsa, boshqaruvchi qulga aylanadi. Ochiq drenaj chiqarish rejimi bilan yaxshi birlashadi, ammo bu boshqa hikoya.

Boshqa hamma narsa kabi, STM32 da SPI funksionallikka boy, bu esa uni tushunishni biroz qiyinlashtiradi. Misol uchun, u nafaqat SPI, balki I2S interfeysi bilan ham ishlashi mumkin va hujjatlarda ularning tavsiflari aralashtiriladi, ortiqcha narsalarni o'z vaqtida kesib tashlash kerak. Bizning vazifamiz juda oddiy: biz faqat MOSI va SCK yordamida ma'lumotlarni yuborishimiz kerak. Biz 25.3.4 bo'limiga o'tamiz (yarim dupleks aloqa, yarim dupleks aloqa), u erda biz topamiz 1 ta soat va 1 ta bir yo'nalishli ma'lumot simi (1 soat signali va 1 ta bir yo'nalishli ma'lumotlar oqimi):

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Ushbu rejimda dastur SPI dan faqat uzatish yoki faqat qabul qilish rejimida foydalanadi. / Faqat uzatish rejimi dupleks rejimiga o'xshaydi: ma'lumotlar uzatish pinida uzatiladi (MOSI asosiy rejimda yoki MISO tobe rejimda) va qabul qilish pinidan (mos ravishda MISO yoki MOSI) oddiy kiritish/chiqarish pin sifatida foydalanish mumkin . Bunday holda, dastur faqat Rx buferini e'tiborsiz qoldirishi kerak (agar u o'qilsa, u erda uzatilgan ma'lumotlar bo'lmaydi).

Ajoyib, MISO pin bepul, keling, unga LAT signalini ulaymiz. Slave Select-ni ko'rib chiqaylik, bu STM32-da dasturiy jihatdan boshqarilishi mumkin, bu juda qulay. Biz xuddi shu nomdagi paragrafni 25.3.1 SPI bo'limida o'qiymiz Umumiy tavsif:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Dasturiy ta'minotni boshqarish NSS (SSM = 1) / Slave tanlash ma'lumotlari SPI_CR1 registrining SSI bitida mavjud. Tashqi NSS pin boshqa ilovalar ehtiyojlari uchun bepul qoladi.

Registrlarga yozish vaqti keldi. Men SPI2 dan foydalanishga qaror qildim, uning asosiy manzilini ma'lumotlar jadvalidan qidiring - 3.3 Xotira xaritasi bo'limida:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Xo'sh, boshlaylik:

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

25.3.3 bo'limini o'z-o'zidan tushunarli sarlavha bilan oching: "Master rejimda SPI konfiguratsiyasi":

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

1. SPI_CR2 registrida BR[0:1] bitlari bilan ketma-ket soat chastotasini o'rnating.

Registrlar xuddi shu nomdagi ma'lumotnoma bo'limida to'plangan. Manzil siljishi (Manzil ofset) CR1 - 0x00 uchun, sukut bo'yicha barcha bitlar tozalanadi (Qiymatni tiklash 0x0000):

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

BR bitlari boshqaruvchi soat ajratgichni o'rnatadi, shu bilan SPI ishlaydigan chastotani aniqlaydi. Bizning STM32 chastotamiz 72 MGts bo'ladi, LED drayveri, ma'lumotlar varag'iga ko'ra, 25 MGts gacha chastotada ishlaydi, shuning uchun biz to'rtga bo'lishimiz kerak (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. Ma'lumot uzatish va ketma-ket soat vaqti o'rtasidagi munosabatni aniqlash uchun CPOL va CPHA bitlarini o'rnating (240-betdagi diagrammaga qarang)

Biz bu erda ma'lumotlar varag'ini o'qiyotganimiz va sxemalarni ko'rib chiqmaganimiz sababli, keling, 704-betdagi CPOL va CPHA bitlarining matn tavsifini batafsil ko'rib chiqaylik (SPI Umumiy tavsifi):

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Soat fazasi va polaritesi
SPI_CR1 registrining CPOL va CPHA bitlaridan foydalanib, siz to'rtta vaqt munosabatlarini dasturiy ravishda tanlashingiz mumkin. CPOL (soat polaritesi) biti hech qanday ma'lumot uzatilmaganda soat signalining holatini nazorat qiladi. Bu bit master va slave rejimlarini boshqaradi. Agar CPOL qayta o'rnatilsa, dam olish rejimida SCK pin past bo'ladi. Agar CPOL biti o'rnatilgan bo'lsa, dam olish rejimida SCK pin yuqori bo'ladi.
CPHA (soat fazasi) biti o'rnatilganda, yuqori bitli tuzoq strobi SCK signalining ikkinchi chetidir (CPOL aniq bo'lsa tushadi, CPOL o'rnatilgan bo'lsa ko'tariladi). Ma'lumotlar soat signalining ikkinchi o'zgarishi bilan ushlanadi. Agar CPHA biti aniq bo'lsa, yuqori bitli tuzoq strobi SCK signalining ko'tarilgan qirrasidir (CPOL o'rnatilgan bo'lsa, pastga tushadigan chekka, CPOL o'chirilgan bo'lsa, ko'tarilgan chekka). Ma'lumotlar soat signalining birinchi o'zgarishida ushlanadi.

Ushbu bilimlarni o'zlashtirib, biz ikkala bit ham nol bo'lib qolishi kerak degan xulosaga keldik, chunki Biz SCK signali ishlatilmayotganda past bo'lishini va ma'lumotlar pulsning ko'tarilgan chetida uzatilishini xohlaymiz (XNUMX-rasmga qarang). Rising Edge DM634 ma'lumotlar varag'ida).

Aytgancha, biz birinchi marta ST ma'lumotlar varaqlaridagi lug'atning xususiyatiga duch keldik: ularda "bitni nolga qaytarish" iborasi yozilgan. biroz tiklash uchun, va emas bir oz tozalash uchun, masalan, Atmega kabi.

3. Ma'lumotlar bloki 8-bit yoki 16-bit formatda ekanligini aniqlash uchun DFF bitini o'rnating

DM16 kabi 634-bitli PWM ma'lumotlarini uzatish bilan bezovta qilmaslik uchun men 12-bitli DM633-ni oldim. DFFni bittaga o'rnatish mantiqan:

#define DFF         0x0800

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

4. Blok formatini aniqlash uchun SPI_CR1 registridagi LSBFIRST bitini sozlang

LSBFIRST, uning nomidan ko'rinib turibdiki, birinchi navbatda eng kam ahamiyatli bit bilan uzatishni sozlaydi. Ammo DM634 eng muhim bitdan boshlab ma'lumotlarni olishni xohlaydi. Shuning uchun biz uni qayta tiklashni qoldiramiz.

5. Uskuna rejimida, agar NSS pinidan kiritish kerak bo'lsa, butun bayt uzatish ketma-ketligi davomida NSS piniga yuqori signalni qo'llang. NSS dasturiy ta'minot rejimida SPI_CR1 registrida SSM va SSI bitlarini o'rnating. Agar NSS pinini chiqish sifatida ishlatish kerak bo'lsa, faqat SSOE bitini o'rnatish kerak.

NSS apparat rejimini unutish uchun SSM va SSI ni o'rnating:

#define SSI         0x0100
#define SSM         0x0200

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

6. MSTR va SPE bitlari o'rnatilishi kerak (ular faqat NSS signali yuqori bo'lsa o'rnatilgan bo'lib qoladi)

Aslida, ushbu bitlar bilan biz SPI-ni master sifatida belgilaymiz va uni yoqamiz:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//когда все готово, включаем SPI
_SPI2_ (_SPI_CR1) |= SPE;

SPI sozlangan, keling, darhol drayverga bayt yuboradigan funktsiyalarni yozaylik. 25.3.3 "SPI-ni asosiy rejimda sozlash" ni o'qishni davom eting:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Ma'lumotlarni uzatish tartibi
Transmissiya Tx buferiga bayt yozilganda boshlanadi.
Ma'lumotlar bayti da smenali registrga yuklanadi parallel rejimi (ichki avtobusdan) birinchi bitni uzatish paytida, undan keyin u uzatiladi ketma-ket MOSI pin rejimi, CPI_CR1 registridagi LSBFIRST bitining sozlanishiga qarab birinchi yoki oxirgi bit oldinga. TXE bayrog'i ma'lumotlarni uzatishdan keyin o'rnatiladi Tx buferidan siljish registriga, shuningdek, CPI_CR1 registridagi TXEIE biti o'rnatilgan bo'lsa, uzilish hosil qiladi.

Men STM kontrollerlarida SPIni amalga oshirishning bir xususiyatiga e'tiborni qaratish uchun tarjimada bir nechta so'zlarni ta'kidladim. Atmega-da TXE bayrog'i (Tx bo'sh, Tx bo'sh va ma'lumotlarni qabul qilishga tayyor) faqat butun bayt yuborilgandan keyin o'rnatiladi tashqarida. Va bu erda bu bayroq ichki siljish registriga bayt kiritilgandan so'ng o'rnatiladi. U yerga barcha bitlar bilan bir vaqtning o'zida (parallel ravishda) surilganligi va keyin ma'lumotlar ketma-ket uzatilganligi sababli, TXE bayt to'liq yuborilishidan oldin o'rnatiladi. Bu muhim, chunki LED drayverimiz bo'lsa, biz yuborganimizdan keyin LAT pinini tortib olishimiz kerak всех ma'lumotlar, ya'ni. Biz uchun faqat TXE bayrog'i etarli bo'lmaydi.

Bu bizga boshqa bayroq kerakligini anglatadi. Keling, 25.3.7 - "Holat bayroqlari" ni ko'rib chiqaylik:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
<...>
Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
BUSY bayrog'i
BSY bayrog'i apparat tomonidan o'rnatiladi va tozalanadi (unga yozish hech qanday ta'sir qilmaydi). BSY bayrog'i SPI aloqa qatlamining holatini ko'rsatadi.
Qayta tiklaydi:
uzatish tugallanganda (agar uzatish uzluksiz bo'lsa, asosiy rejimdan tashqari)
SPI o'chirilganda
asosiy rejim xatosi yuzaga kelganda (MODF = 1)
Agar uzatish uzluksiz bo'lsa, har bir ma'lumot uzatish o'rtasida BSY bayrog'i o'chiriladi

OK, bu foydali bo'ladi. Keling, Tx buferi qayerda joylashganligini bilib olaylik. Buning uchun "SPI ma'lumotlar registrini" o'qing:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Bitlar 15:0 DR[15:0] Ma'lumotlar registri
Qabul qilingan yoki uzatiladigan ma'lumotlar.
Ma'lumotlar registri ikkita buferga bo'linadi - biri yozish uchun (uzatuvchi bufer) va ikkinchisi o'qish uchun (qabul buferi). Ma'lumotlar registriga yozish Tx buferiga yoziladi va ma'lumotlar registridan o'qish Rx buferidagi qiymatni qaytaradi.

Xo'sh, TXE va BSY bayroqlari joylashgan holat registrida:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Biz yozamiz:

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

Xo'sh, biz LED drayverlarining chiqishlari soniga ko'ra 16 marta ikki baytni uzatishimiz kerak, shunga o'xshash narsa:

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

Lekin biz LAT pinini qanday tortib olishni hali bilmaymiz, shuning uchun biz I/O ga qaytamiz.

Pinlarni tayinlash

STM32F1-da pinlarning holati uchun mas'ul bo'lgan registrlar juda g'ayrioddiy. Ularning Atmega'dan ko'proq ekanligi aniq, lekin ular boshqa STM chiplaridan ham farq qiladi. 9.1-bo'lim GPIO ning umumiy tavsifi:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Umumiy maqsadli kirish/chiqarish portlarining har biri (GPIO) ikkita 32-bitli konfiguratsiya registrlari (GPIOx_CRL va GPIOx_CRH), ikkita 32-bitli maʼlumotlar registrlari (GPIOx_IDR va GPIOx_ODR), 32-bitli sozlash/qayta oʻrnatish registrlari (GPIOx_BSRR), 16-bitli qayta oʻrnatish registrlari (GPIOx_BRR) va 32- bit blokirovkalash registri (GPIOx_LCKR).

Birinchi ikkita registr g'ayrioddiy va ayni paytda juda noqulay, chunki 16 ta port pinlari ular bo'ylab "birodar uchun to'rt bit" formatida tarqalgan. Bular. noldan ettigacha bo'lgan pinlar CRLda, qolganlari esa CRHda. Shu bilan birga, qolgan registrlar portning barcha pinlarining bitlarini muvaffaqiyatli o'z ichiga oladi - ko'pincha qolgan yarmi "zahiralangan".

Oddiylik uchun keling, ro'yxatning oxiridan boshlaylik.

Bizga blokirovka registri kerak emas.

O'rnatish va qayta o'rnatish registrlari juda kulgili, chunki ular bir-birini qisman takrorlaydi: siz hamma narsani faqat BSRR-da yozishingiz mumkin, bu erda 16 bitdan yuqori bo'lsa, pin nolga o'rnatiladi, pastroqlari esa 1 ga o'rnatiladi yoki siz ham mumkin. BRR dan foydalaning, uning pastki 16 biti faqat pinni qayta o'rnatadi. Menga ikkinchi variant yoqadi. Ushbu registrlar muhim ahamiyatga ega, chunki ular pinlarga atomik kirishni ta'minlaydi:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Atom sozlamalari yoki qayta o'rnatish
GPIOx_ODR ni bit darajasida dasturlashda uzilishlarni o'chirishning hojati yo'q: bir yoki bir nechta bitni bitta atomik yozish operatsiyasi APB2 bilan o'zgartirish mumkin. Bunga o'zgartirish kerak bo'lgan bitning o'rnatish/qayta tiklash registriga (GPIOx_BSRR yoki faqat qayta o'rnatish uchun GPIOx_BRR) "1" yozish orqali erishiladi. Boshqa bitlar o'zgarishsiz qoladi.

Ma'lumotlar registrlari o'z-o'zidan tushunarli nomlarga ega - IDR = kirish Yo'nalish registri, kiritish registri; ODR = chiqish Yo'nalish registri, chiqish registri. Hozirgi loyihada bizga kerak bo'lmaydi.

Va nihoyat, nazorat registrlari. Bizni ikkinchi SPI pinlari, ya'ni PB13, PB14 va PB15 qiziqtirganligi sababli, biz darhol CRH ga qaraymiz:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Va biz 20 dan 31 gacha bo'lgan bitlarda biror narsani yozishimiz kerakligini ko'ramiz.

Yuqorida biz pinlardan nimani xohlashimizni allaqachon aniqlab oldik, shuning uchun bu erda men skrinshotsiz qilaman, men shuni aytamanki, MODE yo'nalishni (har ikkala bit 0 ga o'rnatilgan bo'lsa, kiritish) va pin tezligini (bizga 50 MGts kerak, ya'ni. ikkala pin ham “1” ga), va CNF rejimni o'rnatadi: oddiy “surish-pull” – 00, “muqobil” – 10. Odatiy bo'lib, yuqorida ko'rib turganimizdek, barcha pinlar pastdan uchinchi bitga ega (CNF0), ularni rejimga o'rnatadi suzuvchi kirish.

Men ushbu chip bilan boshqa biror narsa qilishni rejalashtirganim uchun, soddaligi uchun men pastki va yuqori boshqaruv registrlari uchun barcha mumkin bo'lgan MODE va ​​CNF qiymatlarini aniqladim.

Qandaydir tarzda shunday

#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

Bizning pinlarimiz B portida joylashgan (asosiy manzil - 0x40010C00), kod:

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

Va shunga ko'ra, siz BRR va BSRR registrlari tomonidan o'zgartiriladigan LAT uchun ta'riflarni yozishingiz mumkin:

/*** 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 faqat inertsiya bo'yicha, har doim shunday bo'lgan, qolsin)

Endi hamma narsa ajoyib, lekin u ishlamayapti. Bu STM32 bo'lgani uchun ular elektr energiyasini tejaydi, ya'ni siz kerakli atrof-muhit birliklarining soat rejimini yoqishingiz kerak.

Soatni yoqing

Soat, shuningdek, Clock deb nomlanuvchi, soat uchun javobgardir. Va biz RCC qisqartmasini allaqachon payqashimiz mumkin edi. Biz buni hujjatlarda qidiramiz: bu Reset va Clock Control.

Yuqorida ta'kidlab o'tilganidek, xayriyatki, soat mavzusining eng qiyin qismini biz uchun STM odamlari qilishdi, buning uchun biz ularga katta rahmat (yana bir bor havola beraman) Di Halt veb-sayti, qanchalik chalkashligini aniq qilish uchun). Bizga faqat periferik soatni yoqish uchun mas'ul registrlar kerak (Periferik soatni yoqish registrlari). Birinchidan, RCC ning asosiy manzilini topamiz, u "Xotira xaritasi" ning boshida joylashgan:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

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

Va keyin yoki plastinada biror narsani topishga harakat qiladigan havolani bosing yoki yaxshiroq bo'lgan bo'limlardan faollashtiruvchi registrlarning tavsiflarini ko'rib chiqing. registrlarni yoqish. RCC_APB1ENR va RCC_APB2ENRni qaerdan topamiz:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Va ular, shunga ko'ra, SPI2, IOPB (I/O Port B) va muqobil funktsiyalarni (AFIO) soatini o'z ichiga olgan bitlarni o'z ichiga oladi.

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

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

//включаем тактирование порта B и альт. функций
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//включаем  тактирование SPI2
_RCC_(_APB1ENR) |= SPI2EN;

Yakuniy kodni topish mumkin shu yerda.

Agar sizda sinab ko'rish imkoniyati va xohishingiz bo'lsa, unda DM634 ni quyidagicha ulang: DAI dan PB15 ga, DCK dan PB13 ga, LAT dan PB14 ga. Biz drayverni 5 voltdan quvvatlaymiz, erga ulashni unutmang.

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

STM8 PWM

STM8 da PWM

Men ushbu maqolani endigina rejalashtirayotganimda, men, misol tariqasida, etiksiz poyafzal tikib qolmaslik uchun faqat ma'lumotlar varag'idan foydalanib, notanish chipning ba'zi funksiyalarini o'zlashtirishga qaror qildim. STM8 bu rol uchun ideal edi: birinchidan, menda STM8S103 o'rnatilgan bir nechta xitoy platalari bor edi, ikkinchidan, u unchalik mashhur emas, shuning uchun Internetda o'qish va yechim topish vasvasasi aynan shu echimlarning yo'qligiga bog'liq.

Chipda ham bor tafsilotli ro'yxat и Ma'lumotnoma RM0016, birinchisida pinout va ro'yxatga olish manzillari mavjud, ikkinchisida - hamma narsa. STM8 C da dahshatli IDE da dasturlashtirilgan ST Visual Develop.

Soat va kiritish/chiqarish

Odatiy bo'lib, STM8 2 MGts chastotada ishlaydi, bu darhol tuzatilishi kerak.

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
HSI (yuqori tezlikli ichki) soat
HSI soat signali dasturlashtiriladigan ajratgichga ega (16 dan 1 gacha) ichki 8 MGts chastotali RC osilatoridan olinadi. U soatni ajratuvchi registrda (CLK_CKDIVR) o'rnatiladi.
Eslatma: boshida soat signalining etakchi manbai sifatida 8 bo'linuvchiga ega HSI RC osilatori tanlanadi.

Biz registr manzilini ma'lumotlar varag'ida, tavsifni refmanda topamiz va registrni tozalash kerakligini ko'ramiz:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Biz PWM-ni ishga tushiramiz va LEDlarni ulaymiz, keling, pinoutni ko'rib chiqaylik:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Chip kichik, ko'plab funktsiyalar bir xil pinlarda to'xtatilgan. Kvadrat qavs ichida "muqobil funksionallik" bo'lib, u "opsiya baytlari" bilan almashtiriladi (variant baytlari) - Atmega sigortalari kabi narsa. Siz ularning qiymatlarini dasturiy jihatdan o'zgartirishingiz mumkin, ammo bu shart emas, chunki Yangi funksiya faqat qayta ishga tushirilgandan so'ng faollashadi. Ushbu baytlarni o'zgartirishi mumkin bo'lgan ST Visual Programmer (Visual Develop bilan yuklab olingan) dan foydalanish osonroq. Pinout birinchi taymerning CH1 va CH2 pinlari kvadrat qavslar ichida yashiringanligini ko'rsatadi; STVPda AFR1 va AFR0 bitlarini o'rnatish kerak, ikkinchisi esa ikkinchi taymerning CH1 chiqishini PD4 dan PC5 ga o'tkazadi.

Shunday qilib, 6 ta pin LEDlarni boshqaradi: birinchi taymer uchun PC6, PC7 va PC3, ikkinchisi uchun PC5, PD3 va PA3.

STM8 da I/U pinlarini o'rnatish STM32 ga qaraganda sodda va mantiqiyroq:

  • Atmega DDR ma'lumotlar yo'nalishi registridan tanish (Ma'lumotlar yo'nalishi registri): 1 = chiqish;
  • birinchi boshqaruv registri CR1, chiqarilganda, surish rejimini (1) yoki ochiq drenajni (0) o'rnatadi; LEDlarni katodlar bilan chipga ulaganim uchun bu erda nollarni qoldiraman;
  • ikkinchi nazorat registri CR2, chiqarilganda, soat tezligini o'rnatadi: 1 = 10 MGts

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

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

PWM sozlamalari

Birinchidan, keling, atamalarni aniqlaymiz:

  • PWM chastotasi – taymer belgilanishi chastotasi;
  • Avtomatik qayta yuklash, AR – taymer hisoblaydigan avtomatik yuklanadigan qiymat (puls davri);
  • Yangilanish hodisasi, UEV – taymer AR ga hisoblaganda sodir bo‘ladigan hodisa;
  • PWM ish aylanishi - PWM ish aylanishi, ko'pincha "vazifa omili" deb ataladi;
  • Qiymatni olish/taqqoslash – taymer hisoblagan suratga olish/taqqoslash qiymati nimadir qiladi (PWM holatida u chiqish signalini o'zgartiradi);
  • Oldindan yuklash qiymati - oldindan yuklangan qiymat. Qiymatni solishtiring taymer belgilanayotganda o'zgartirilmaydi, aks holda PWM sikli buziladi. Shunday qilib, yangi uzatilgan qiymatlar buferga joylashtiriladi va taymer ortga hisoblashning oxiriga yetganda va qayta tiklanganda chiqariladi;
  • Chetga tekislangan и Markazga tekislangan rejimlar - chegara bo'ylab va markazda, Atmel bilan bir xil Tez PWM и Fazali to'g'ri PWM.
  • OCiREF, Chiqishni solishtirish mos yozuvlar signali – mos yozuvlar chiqish signali, aslida PWM rejimida mos keladigan pinda paydo bo'ladigan narsa.

Pinoutdan allaqachon aniq bo'lganidek, ikkita taymer PWM qobiliyatiga ega - birinchi va ikkinchi. Ikkalasi ham 16 bitli, birinchisi juda ko'p qo'shimcha funktsiyalarga ega (xususan, u yuqoriga ham, pastga ham hisoblashi mumkin). Ikkalamiz ham birdek ishlashimiz kerak, shuning uchun tasodifan yo'q narsani ishlatmaslik uchun ikkinchisidan, shubhasiz, kambag'aldan boshlashga qaror qildim. Muammo shundaki, ma'lumotnomadagi barcha taymerlarning PWM funksiyalarining tavsifi birinchi taymer haqidagi bobda (17.5.7 PWM rejimi), shuning uchun siz hujjat bo'ylab doimo oldinga va orqaga o'tishingiz kerak.

STM8-dagi PWM Atmega-dagi PWM-dan muhim afzalliklarga ega:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Chegara tekislangan PWM
Hisob konfiguratsiyasi pastdan yuqoriga
Agar TIM_CR1 registridagi DIR biti tozalansa, pastdan yuqoriga hisoblash faol bo'ladi
misol
Misol birinchi PWM rejimidan foydalanadi. PWM mos yozuvlar signali OCiREF TIM1_CNT < TIM1_CCRi bo'lganda yuqori saqlanadi. Aks holda, u past darajani oladi. Agar TIM1_CCRi registridagi taqqoslash qiymati avtomatik yuklash qiymatidan (TIM1_ARR registri) katta bo'lsa, OCiREF signali 1 da saqlanadi. Taqqoslash qiymati 0 bo'lsa, OCiREF nolga teng bo'ladi....

davomida STM8 taymer yangilanish hodisasi avval tekshiradi qiymatini solishtiring, va shundan keyingina mos yozuvlar signalini ishlab chiqaradi. Atmega taymeri avval vidalanadi va keyin taqqoslaydi, natijada compare value == 0 chiqish igna bo'lib, uni qandaydir tarzda hal qilish kerak (masalan, mantiqni dasturiy ravishda o'zgartirish orqali).

Shunday qilib, biz nima qilmoqchimiz: 8-bitli PWM (AR == 255), pastdan yuqoriga sanash, chegara bo'ylab tekislash. Lampochkalar katodlar orqali chipga ulanganligi sababli, PWM 0 (LED yoqilgan)gacha chiqishi kerak. qiymatini solishtiring va 1 dan keyin.

Biz allaqachon ba'zilari haqida o'qiganmiz PWM rejimi, shuning uchun biz ushbu iborani (18.6.8 - TIMx_CCMR1) mos yozuvlar qo'llanmasidan izlash orqali ikkinchi taymerning kerakli registrini topamiz:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
110: Birinchi PWM rejimi - pastdan yuqoriga sanashda, TIMx_CNT < TIMx_CCR1 bo'lganda birinchi kanal faol bo'ladi. Aks holda, birinchi kanal faol emas. [bundan keyin hujjatda taymer 1dan noto'g'ri nusxa ko'chirish-joylashtirish mavjud] 111: Ikkinchi PWM rejimi - pastdan yuqoriga sanashda birinchi kanal TIMx_CNT < TIMx_CCR1 bo'lganda faol emas. Aks holda, birinchi kanal faol bo'ladi.

LEDlar MK ga katodlar orqali ulanganligi sababli, ikkinchi rejim bizga mos keladi (birinchisi ham, lekin biz buni hali bilmaymiz).

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Bit 3 OC1PE: 1-pinni oldindan yuklashni yoqing
0: TIMx_CCR1 da oldindan yuklash registri o'chirilgan. TIMx_CCR1 ga istalgan vaqtda yozishingiz mumkin. Yangi qiymat darhol ishlaydi.
1: TIMx_CCR1 da oldindan yuklash registri yoqilgan. O'qish/yozish operatsiyalari oldindan yuklash registriga kirish imkonini beradi. Oldindan yuklangan TIMx_CCR1 qiymati har bir yangilanish hodisasi davomida soya registriga yuklanadi.
*Izoh: PWM rejimi to'g'ri ishlashi uchun oldindan yuklash registrlari yoqilgan bo'lishi kerak. Bu yagona signal rejimida kerak emas (OPM biti TIMx_CR1 registrida o'rnatiladi).

Xo'sh, keling, ikkinchi taymerning uchta kanali uchun kerak bo'lgan hamma narsani yoqaylik:

#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 ikkita sakkiz bitli registrdan iborat, hammasi oddiy:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Ikkinchi taymer faqat pastdan yuqoriga hisoblashi mumkin, chegara bo'ylab hizalanish, hech narsani o'zgartirish kerak emas. Chastota bo'luvchini, masalan, 256 ga o'rnatamiz. Ikkinchi taymer uchun bo'luvchi TIM2_PSCR registrida o'rnatiladi va ikkining kuchiga teng:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Qolgan narsa - xulosalar va ikkinchi taymerning o'zini yoqish. Birinchi muammo registrlar tomonidan hal qilinadi Rasmga olish/taqqoslash yoqish: ular bo'ylab assimetrik tarzda tarqalgan ikkita, uchta kanal mavjud. Bu erda biz signalning polaritesini o'zgartirish mumkinligini ham bilib olamiz, ya'ni. printsipial jihatdan, PWM rejimidan foydalanish mumkin edi 1. Biz yozamiz:

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

Va nihoyat, biz TIMx_CR1 registrida taymerni ishga tushiramiz:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Keling, AnalogWrite() ning oddiy analogini yozamiz, u haqiqiy qiymatlarni taqqoslash uchun taymerga o'tkazadi. Registrlar taxminiy nomlanadi Registrlarni olish/taqqoslash, har bir kanal uchun ulardan ikkitasi bor: TIM8_CCRxL da past tartibli 2 bit va TIM2_CCRxH da yuqori tartibli. Biz 8-bitli PWM-ni yaratganimiz uchun faqat eng muhim bitlarni yozish kifoya:

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

Diqqatli o'quvchi bizda 100% to'ldirishni ishlab chiqara olmaydigan biroz nuqsonli PWM borligini payqaydi (maksimal 255 qiymatida signal bir taymer aylanishiga teskari bo'ladi). LEDlar uchun bu muhim emas va diqqatli o'quvchi uni qanday tuzatish kerakligini allaqachon taxmin qilishi mumkin.

Ikkinchi taymerda PWM ishlaydi, keling, birinchisiga o'tamiz.

Birinchi taymer bir xil registrlarda aynan bir xil bitlarga ega (shunchaki ikkinchi taymerda "zahiralangan" bo'lgan bitlar birinchisida barcha turdagi ilg'or narsalar uchun faol ishlatiladi). Shuning uchun, ma'lumotlar varag'ida bir xil registrlarning manzillarini topish va kodni nusxalash kifoya. Xo'sh, chastota bo'luvchining qiymatini o'zgartiring, chunki ... birinchi taymer ikkining kuchini emas, balki ikkita registrda aniq 16 bitli qiymatni olishni xohlaydi Prescaler High и past. Biz hamma narsani qilamiz va... birinchi taymer ishlamayapti. Nima gap?

Muammoni faqat 1-taymerning boshqaruv registrlari haqidagi to'liq bo'limni ko'rib chiqish orqali hal qilish mumkin, bu erda biz ikkinchi taymerda mavjud bo'lmaganini qidiramiz. Bo'ladi 17.7.30 Tanaffus registri (TIM1_BKR), bu bit qaerda:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Asosiy chiqishni yoqish

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Hammasi aniq, kod bir joyda.

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

STM8 Multipleks

STM8 da multiplekslash

Uchinchi mini-loyiha sakkizta RGB LEDni PWM rejimida ikkinchi taymerga ulash va ularni turli xil ranglarda ko'rsatishdir. Bu LED multiplekslash kontseptsiyasiga asoslanadi, ya'ni agar siz LEDlarni juda tez yoqsangiz va o'chirsangiz, ular doimo yonib turgandek tuyuladi (ko'rishning barqarorligi, vizual idrokning inertsiyasi). Men bir marta qilganman Arduino-da shunga o'xshash narsa.

Ish algoritmi quyidagicha ko'rinadi:

  • birinchi RGB LED anodini uladi;
  • uni yoqing, katodlarga kerakli signallarni yuboring;
  • PWM tsiklining oxirigacha kutdi;
  • ikkinchi RGB LED anodini uladi;
  • yoqdi...

Xo'sh, va hokazo. Albatta, chiroyli ishlash uchun anodning ulanishi va LED bir vaqtning o'zida "yoqilishi" talab qilinadi. Xo'sh, yoki deyarli. Qanday bo'lmasin, biz ikkinchi taymerning uchta kanalida qiymatlarni chiqaradigan kodni yozishimiz kerak, UEV ga yetganda ularni o'zgartiramiz va ayni paytda faol RGB LEDni o'zgartiramiz.

LEDni almashtirish avtomatik bo'lgani uchun biz "video xotira" ni yaratishimiz kerak, undan uzilishlar ishlov beruvchisi ma'lumotlarni oladi. Bu oddiy massiv:

uint8_t colors[8][3];

Muayyan LEDning rangini o'zgartirish uchun ushbu massivga kerakli qiymatlarni yozish kifoya qiladi. Va o'zgaruvchi faol LED soni uchun javobgar bo'ladi

uint8_t cnt;

Demux

To'g'ri multiplekslash uchun bizga, g'alati darajada, CD74HC238 demultipleksator kerak. Demultiplexer - apparatda operatorni amalga oshiradigan chip <<. Uchta kirish pinlari (bitlar 0, 1 va 2) orqali biz unga uch bitli X raqamini beramiz va bunga javoban u chiqish raqamini faollashtiradi (1<<X). Chipning qolgan kirishlari butun dizaynni o'lchash uchun ishlatiladi. Bizga ushbu chip nafaqat mikrokontrollerning ishg'ol qilingan pinlari sonini kamaytirish uchun, balki xavfsizlik uchun ham kerak - tasodifan iloji boricha ko'proq LEDlarni yoqmaslik va MKni yoqmaslik uchun. Chip bir tiyin turadi va har doim uy dori kabinetida saqlanishi kerak.

Bizning CD74HC238 kerakli LEDning anodiga kuchlanish berish uchun javobgar bo'ladi. To'liq huquqli multipleksda u P-MOSFET orqali ustunni kuchlanish bilan ta'minlaydi, ammo bu demoda bu to'g'ridan-to'g'ri mumkin, chunki ko'ra, u 20 mA tortadi mutlaq maksimal reytinglar ma'lumotlar varag'ida. Kimdan CD74HC238 ma'lumotlar jadvali Bizga pinoutlar va bu hiyla-nayranglar kerak:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
H = yuqori kuchlanish darajasi, L = past kuchlanish darajasi, X - ahamiyat bermang

Biz E2 va E1 ni erga, E3, A0, A1 va A3 ni STM5 ning PD3, PC4, PC5 va PC8 pinlariga ulaymiz. Yuqoridagi jadval past va yuqori darajalarni o'z ichiga olganligi sababli, biz bu pinlarni surish pinlari sifatida sozlaymiz.

PWM

Ikkinchi taymerdagi PWM avvalgi hikoyada bo'lgani kabi ikkita farq bilan sozlangan:

Birinchidan, biz uzilishni yoqishimiz kerak Tadbirni yangilash (UEV) faol LEDni almashtiruvchi funksiyani chaqiradi. Bu bitni o'zgartirish orqali amalga oshiriladi Yangilash uzilishini yoqish ismli reestrda

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
Ro'yxatga olishni faollashtirishni to'xtatish

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Ikkinchi farq, masalan, multiplekslash hodisasi bilan bog'liq gölgelenme - diodlarning parazit porlashi. Bizning holatda, bu UEV-da uzilishga sabab bo'lgan taymer belgini qo'yishda davom etishi va taymer pinlarga biror narsa yozishni boshlashdan oldin uzilishni ishlov beruvchining LEDni almashtirishga vaqti yo'qligi sababli paydo bo'lishi mumkin. Bunga qarshi kurashish uchun siz mantiqni o'zgartirishingiz kerak bo'ladi (0 = maksimal yorqinlik, 255 = hech narsa yonmaydi) va ekstremal ish aylanishi qiymatlaridan qochishingiz kerak. Bular. UEVdan keyin LEDlarning bir PWM aylanishi uchun to'liq o'chganligiga ishonch hosil qiling.

Polaritni o'zgartirish:

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

r, g va b ni 255 ga o'rnatishdan saqlaning va ulardan foydalanganda ularni teskari aylantirishni unutmang.

Xalaqit beradi

Interruptning mohiyati shundan iboratki, ma'lum sharoitlarda chip asosiy dasturni bajarishni to'xtatadi va ba'zi tashqi funktsiyani chaqiradi. Taymer, shu jumladan, tashqi yoki ichki ta'sirlar tufayli uzilishlar sodir bo'ladi.

Biz ST Visual Develop-da birinchi marta loyiha yaratganimizda, bundan tashqari main.c biz sirli faylga ega oynani oldik stm8_interrupt_vector.c, avtomatik ravishda loyihaga kiritiladi. Bu faylda har bir uzilishga funksiya tayinlangan NonHandledInterrupt. Biz funktsiyamizni kerakli uzilishga bog'lashimiz kerak.

Ma'lumotlar jadvalida uzilish vektorlari jadvali mavjud bo'lib, u erda biz keraklilarini topamiz:

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar
13 TIM2 yangilanishi/to‘lib ketishi
14 TIM2 suratga olish/taqqoslash

UEVda LEDni o'zgartirishimiz kerak, shuning uchun biz №13 uzilishga muhtojmiz.

Shunga ko'ra, birinchi navbatda, faylda stm8_interrupt_vector.c № 13 (IRQ13) uzilish uchun mas'ul funktsiyaning standart nomini o'zingiznikiga o'zgartiring:

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

Ikkinchidan, biz fayl yaratishimiz kerak main.h quyidagi tarkib bilan:

#ifndef __MAIN_H
#define __MAIN_H

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

Va nihoyat, ushbu funktsiyani o'zingizga yozing 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;
}

Faqat uzilishlarni yoqish qoladi. Bu assembler buyrug'i yordamida amalga oshiriladi rim - uni ichidan qidirishingiz kerak bo'ladi Dasturlash bo'yicha qo'llanma:

//enable interrupts
_asm("rim");

Boshqa assembler buyrug'i sim - uzilishlarni o'chiradi. Noto'g'ri vaqtda yuzaga kelgan uzilish massivni buzmasligi uchun "video xotira" ga yangi qiymatlar yozilayotganda ularni o'chirib qo'yish kerak.

Barcha kod - GitHub-da.

Ma'lumotlar varaqlarini o'qish 2: STM32 da SPI; STM8 da PWM, taymerlar va uzilishlar

Agar hech bo'lmaganda kimdir bu maqolani foydali deb topsa, men uni bekorga yozmadim. Men sharhlar va mulohazalarni qabul qilishdan xursand bo'laman, men hamma narsaga javob berishga harakat qilaman.

Manba: www.habr.com

a Izoh qo'shish