Tag Archives: ARM

STM32F103 ir SD SDIO kortelė

Straipsnis skirtas tiems MCU kurie turi SDIO geležį.

Visur yra straipsniai apie SPI SD kortelės pajungimą arba kur jau rimtesnė techniką, tai SDIO su keturiais duomenų kanalais. Tačiau nebūtina naudoti visus kanalus, galima jungti ir per vieną. Todėl, kad prijungti SD kortelę užtenka 5 laidų: Vcc ir žemė, lieka trys duomenims. Reikia SDIO_SC (clock), SDIO_CMD ir SDIO_D0. Jei norim greitesnio skaitymo- D1, D2, D3.

Surašysiu ką aš dariau, kad šios dienos (2022.12.23) STM32CubeMX pagimdytų veikiantį kodą. Seniau reikėdavo naudoti išorinę biblioteką (dažniausiai FatFS iš elm-chan), dabar šią biblioteką kubikas automatiškai įkelia ir sukonfiguruoja. Dar karta pabrėžių – viską padaro. Nereikia rašyti jokių disk-io paprogramių. Nieko nereikia rašyti.

Pradedam nuo SDIO modulio aktyvavimo:
SDIO
Režimas – 1 bitas, būtinai reikalingas pertraukimas. Nors sako, kad veikia be jo. Man neveikė. DMA galima jungti, bet nepastebėjau ko nors. Kitas parametras: SDIOCLK clock divide factor – pasididinkit, nes ant pilno greičio ne visos SD kortelės gali dirbti (ypač pajungtos ant snarglių). Aš parašiau -4, prie 72MHz SDIO clock.
Continue reading →

STM32F103 ir “tikras” CRC32

STM32F103 (bent jau mano naudojamas) turi hardwarinį CRC32 skaičiuotuvą. Tačiau bėda- kažko tai suskaičiuotas CRC32 neatitinka kokio nors online kalkuliatoriaus rezultatui. Internetas prirašytas visko, bet niekur dorai nepaaiškinta kodėl nesutampa.
Atsakymas labai paprastas- big ar little endian skaičiuoja mūsų MCU ir dar kokia bitų seka.
CRC32 pas STM32 skaičiuojasi 32 bitų skaičiais. Todėl kokį nors baitų (ar raidžių) masyvą reikia papildyti iki kartotinio 4 dydžio. Jei masyvas sudarytas iš 32bitų elementų, reikia pasitikrinti tą “endian”. Poto imti masyvą po 4 baitus, sukuisti bitų seką (gerai, kad yra komanda RBIT, Reverse the bit order in a 32-bit word.), suskaičiuoti su hardware CRC32 rezultatą ir vėl sukuisti bitus su ta pačia komanda. Jei reikia, rezultatą invertuoti.

/* tekstines eilutes CRC skaiciavimas. Kartotinis 4. Netilpe baitai ignoruojami */
uint32_t RealCRC32txt(char * buf)
{
uint32_t len=strlen(buf)/4;
return RealCRC32((uint32_t *) buf, len);
}
 
 
/* CRC skaiciavimas naudojant 32 bitu masyva. Jei tikras masyvas, tai svarbu baitu seka, jei konversija is char/byte masyvo, tada nesvarbu */
uint32_t RealCRC32(uint32_t * buf, uint32_t len) //demesio, kas 4 baitai!
{
uint32_t crc,tmp,i;
 
	  hcrc.State = HAL_CRC_STATE_BUSY;
	__HAL_CRC_DR_RESET(&hcrc);
 
	for(i=0;i<len;i++)
	{
		tmp=buf[i];
		//tmp = ((tmp>>24)&0xff) | ((tmp<<8)&0xff0000) | ((tmp>>8)&0xff00) |  ((tmp<<24)&0xff000000); //baitu sekos konverteris
		tmp = __RBIT(tmp);
		hcrc.Instance->DR = tmp;
	}
	crc = __RBIT(hcrc.Instance->DR);
	hcrc.State = HAL_CRC_STATE_READY;
	return crc;
}

Užkomentuota ilga eilutė atkomentuojama, jei reikia skaičiuoti CRC tikram 32 bitų masyvui.

Teksto “00010002” CRC32= 1366C59F

ARM38: soft PWM pertraukimas

Pratesiant HUB08 temą. Rašiau, kad OE signalo ilgis reguliuoja visos matricos šviesumą. Ir tokiam reguliavimui labai gerai naudoti “single shot” PWM pertraukimą. T.y. paleidžiam taimerį kuris vieną kartą sugeneruoja PWM signalą kurio ilgis nusistato harwariškai. Toliau galimi du variantai- tiesiogiai naudoti PWM signalą OE valdymui arba naudoti PWM signalo pasibaigimo pertraukimą.
Pasinagrinėjam antrą variantą (pirmas variantas skiriasi tik vienu parametru ir laidelio prijungimu prie dedikuotos kojelės).

Čia kubiko ekrano vaizdas. Šiam eksperimentui pasinaudojam laisvu, trečiu taimeriu:
CubeMX
Taimeris dirba nuo 72MHz bazinio clock. Todėl ir tas prescaller toks: 720-1, t.y. 72000kHz/720=100kHz (10μs) žingsniukais reguliuojasi impulso ilgis.
Continue reading →

ARM38: HUB08 ir STM32F1 hardware

Šiais laikais dažnai galima rasti kiniškų LED matricų- ar tai išmestos, ar defektuotos arba nusipirkti pas pačius kinus. Tokias matricas valdo kiniški kontroleriai kurie viską ir atlieka, jei užtenka nervų suprasti kiniško softo kreivumą. Tačiau kartais atsiranda noras sukurti kažką savo ir paaiškėja, kad nelabai yra informacijos apie tas matricas- yra įvairios bibliotekos (gana kreivos) ar šiaip keisti sprendimai, bet pačio aprašymo nėra.
Šiame straipsnelyje pasinagrinėsim vienspalves (vieno ryškumo lygio) LED matricas su HUB08 jungtimi. Šios matricos maitinamos dažniausiai nuo 5V per atskirą jungtį, o informacija perduodama per 16 kontaktų jungtį su užrašu Hub08. Hub08 leidžia jungti matricas į grandinėles (daisy chain) ir kiniški moduliai ir jų softas automatiškai viską sutvarko. Mane domino kiek žemesnio lygio informacija.
hub08 protocol pinout
Kartais vietoje raudonų LED pajungiami ir mėlyni, taip gaunas RGB spalvos ar panašiai.
Continue reading →

Čipų trūkumas 2

Seniau lupinėdavau iš šroto (Husqvarnos žoliapjovės) STM32F103 čipus. Ne tiek jau daug rasdavau, nes dažniausiai čipai užlakuoti. Dabar vėl parvežė, matau keletą nelakuotu, čiumpu ir namie matau klastą:
STM32F103 clone
Tai kinietiškas analogas- ne toks “ekologiškas”, bet sako kad greitesnis. Čipo viduje yra du kristalai- atskirai ROMas ir atskirai MCU. Čipo paleidimo metu programa perrašoma į RAM ir veikia iš ten. Teoriškai gaunasi lėtesnis boot, bet greitesnis kontroleris.
Lygtai pilnai suderinamas su STM produktu, bet tikriausiai yra savų prigulnybių. Čipas užnumeruotas kaip 303, bet čia tikrai ne trečia serija.
Seniau visi čipai buvo STM. Matyt arba taupo pinigus arba tikrai nėra kur pirkti naujų STM (nereikia barstyti).
Continue reading →

ARM37: zuikis ir vėžliukas

Kas nesidomi mikroprocesorių programavimų, gali ir neskaityti. Bus nelabai įdomu… 🙂

Klasikinė bėda- yra du procesai, kurių veikimo greičiai labai skiriasi. Šiam variante: USB ir UART. Kaip suderinti jų bendrą veikimą? Štai imat kokį source code iš interneto platybėse publikuotos pamokėlės, viskas kaip ir veikia kol spaudžiojat duomenis iš klaviatūros, o jei pabandot “copy-paste” ir staiga tekstas pradeda nebepersiduoti, raidės prapuola ir procesoriukas pastringa. Kodėl? Todėl, kad reikia suderinti skirtingo greičio ir veikimo principo procesus:
Pirmas procesas, USB, tai paketinis duomenų perdavimas su galimybe pristabdyti duomenis ar net paprašyti juos pakartoti. Viskas vyksta gana greitai.
Antras procesas, UART, tai nuoseklus, lėtas duomenų perdavimas. Ir pats perdavimas pririštas prie laiko. Jei nenaudojam kontrolinių linijų, procesą negalime sustabdyti. Kai duomenų per daug, jie prarandami.

Taip atrodo iš žmogaus pusės, iš kontrolerio pusės tai jau keturi procesai: USB TX, USB RX, UART TX, UART RX.

Kad suvaldyti šį chaosą, reikia procesus paleisti nepriklausomai, per pertraukimus. Arba, kai siunčiam, tai galima ir pastabdyti pagrindinį ciklą (bent jau šiame eksperimente). Gaunais taip:

  1. UART RX, per pertraukima ir net DMA. Tačiau nežinom kiek baitų gausim, tai visas mūsų DMA/IRQ tvarko tik vieną baitą.
  2. UART TX, siuntimas blokuojant procesoriaus darbą. Mūsų programa nieko protingo nedaro, tai galima blokuoti.
  3. USB RX, tikriausiai per pertraukimą, naudojam HAL biblioteką.
  4. USB TX, blokuojamas ar tai IRQ, naudojam HAL biblioteką*.

Visi procesai per pertraukimą daro tik vieną darbą- jei gaunam duomenis, įrašom duomenis į buferį (jei yra vietos). Buferis vadinasi “circle” nes tai kaip ir cirkuliarinis buferis**, tik aš jo neperpildau, prarandu duomenis jei buffer overflow. O pats smagumas vyksta pagrindiniam, amžinam cikle:

 while(1)
	{
	HAL_IWDG_Refresh(&hiwdg); //watchdogas

	while(circle_available(&cc)>0) //ar yra duomenu gautu is UART?
		{
		i=circle_available(&cc);
		for(j=0;j<i;j++)
			{
			tmp[j]=circle_pull(&cc); //viska persikopijuojam ir issiunciam
			}
		CDC_Transmit_FS(tmp, i); //siuntimas per USB (blocking?. gal ne)
		}

	while(circle_available(&cu)>0) //ar yra duomenu gautu is USB?
		{
		i=circle_available(&cu);
		for(j=0;j<i;j++)
			{
			tmp[j]=circle_pull(&cu); //viska persikopijuojam ir issiunciam
			}
		send_uart((char *) tmp,i); //siunciam per UART (blocking)
		}
	}
}


Tikriausiai senas Wordpresas nenusiaubė programos teksto.

Iš principo programa veikia taip: yra ką perduoti? perduodam! ir vėl iš naujo.

Tačiau galima dar labiau viską užkomplikuoti- TX padaryti su atskirais buferiais ir siuntimo procesą irgi padaryti asinchroninį. Tada procesoriuje išsilaisvintu dar šiek tiek resursų kokiai nors pagrindinei programai.
Dar viena bėda- nenumatytas atvejis, kai trumpuose momentuose, kol ištraukiami duomenys į buferį, kas nors įrašytu naujus duomenis. Teoriškai circle buferis apsaugo nuo tokių nemalonumų… Praktiškai, buitiniams reikalams viskas veikia.

Šis straipsniukas skirtas man pačiam prisiminti, nes reikėjo ir neatsiminiau. Teko kiek parašinėti.

*) HAL USB biblioteka netikrina ar duomenys išėjo. Jei reikalingi TIKRAI gerai daryti, reikia tikrinti USB būklę. Tada jau geriau nagrinėtis ATARI disko emuliatoriaus kodą (rodos ten padariau viską)
**) circular buffer, cirkuliarinis buferis leidžia rašyti ir skaityti duomenis iš buferio. T.y duomenys kaip gyvatėlė Uroboras, nauji duomenys prisideda prie galvos, o seni nusiima prie uodegos. Viskas gerai, kol galva nepasiekia uodegos ir gyvatėlė neįsikanda. Tada prarandam duomenis.
P.S. source kodas neoptimizuotas dėl aiškesnio vaizdavimo.

ARM36: Burbuliniai LED

Antikvarinis LED indikatorius, tikriausiai iš kokio nors tarybinio kalkuliatoriaus. Žãvi savo netobulumu:

burbulinis LED
АЛС318

Simboliai mažyčiai (todėl ir plastikinės linzės), šviesumas mizernas (prie tausojančių srovių). Bet savotiškai žavingas.
Tokiam indikatoriui pajungti reikia gana daug laidų ir dinaminės indikacijos. Demonstracijai panaudojau breadboard ir “bluepill” plokštę (STM32F103C8t)- mikroschema mažoka, beveik visos kojos sunaudojamos indikatoriui. Prie anodų (pliusinių elektrodų) reikia prikabinti kokius nors rezistorius, kad apriboti srovę per LED, tik 3mA statiniam režime per vieną segmentą. Naudojant dinaminę indikaciją leistina srovė 40mA, bet jei indikacija sustos, tai atia LEDams.
Continue reading →

ARM35: LCD ir FSMC

Trumpa priešistorė: prisirinkom kažkokių PCB su STM32F103* mikroschemos ir nežinomu LCD. LCD buvo dviejų tipų, o pačios PCB irgi keletos variantų. Kai kurios su kitu STM32 BGA čipu ir ROM/RAM mikroschemom. Dar kitos PCB beveik tuščios ar pažeistos. Užtat visos turi mėlyną dantį ir visokias smulkmes.
Visokius kištukus gana lengvai išaiškinom (gerai, kad ne visos PCB padengtos laku), kai kurie primityvai kaip LCD pasvietimas (ar dar kieno) eina per tranzistorius, tai irgi lengvai atsibūrė. Bet liko LCD. LCD tikrai dviejų tipų- mažesnis, išjungtas juodas ir didesnis, baltas. Abu ekranai grafiniai, nes yra originali firmwarė, kur parašo kad “atnaujink softą”. Pirminis softas lygtai ir universalus abiem plokštėm ir jame aptikom, kad plokštės iš Husqvarnos automatinių žoliapjovių.
Deja informacijos apie LCD ekranus ar kontrolerius nebuvo visiškai. Todėl ėmiau iš eilės visokius LCD ekranus su panašiu kiekiu pinų ir bandžiau… Pagal įtampas, pagal originalios firmwarės siunčiamus signalus atrinkau, kur maždaug duomenys, kur WR ar panašūs signalai.
Mažesnis LCD labai panašu į ST7565 ir ten viskas maždaug buvo aišku. Didelis LCD visiškai neaiškus.
Dar pasirodė labai keista, kodėl pasirinktas toks keistas pajungimas prie MCU:

PD0=D2
PD1=D3
PD4=RD
PD5=WR
PD7=CS1
PD14=D0
PD15=D1
PE3=A0
PE7=D4
PE8=D5
PE9=D6
PE10=D7

Tačiau pernelyg nesivarginau. Nes svarbiau buvo LCD. Su didesniu LCD buvo bėdos- labai panašus LCD yra UltraChip serijos kontroleriai kaip UC1610 ar UC1611. Tačiau komandos nevisos veikia. Bėda tame, kad daug komandų bendros visos serijos čipams (ar net kito gamintojo čipams), kitos komandos ignoruojamos ar panašiai. Ir dar nustebino pačio LCD ekrano pilkumo atspalvių bitų seka. Net vienu metu kilo mintis, kad ten spalvoto ekrano kontroleris pritvirtintas prie juodai-balto LCD ekrano. Dar kilo mintis, kad neteisingai nurašiau pinoutą (tikrai ne, žr. toliau).
Bežaidžiant su bitais, buvo kaip ir parašytas šioks toks softas ekrano valdymui. Tačiau norint paišyti vaizdą ant ekrano pagal pikselius, reikia nuskaityti informaciją iš ekrano. Tai galima padaryti ir “bit bang” režimu ir su STM32F103 tai vyksta gana greitai. Bet vistiek viskas labai kvaila. Buvo pasiskaitytos instrukcijos, paguglinta ir pasinagrinėtas STMkubikas ir pasirodo man nežinomas FSMC režimas, kur kaikurios MCU kojos pavirsta DATA, ADR ir kontroliniais (WE, CS ir pan) signalais. Tada skaitymas iš LCD ar rašymas į LCD (ar į kokį SRAM) pavirsta paprasta operacija- “rašymas ir skaitymas iš RAM”:

*(__IO unsigned char *)(LCD_DAT_ADDR)=d;
d=*(__IO unsigned char *)(LCD_DAT_ADDR);

Ir mūsų LCD būtent ir pajungtas kaip FSMC įrenginys (dėl to ir toks keistas LCD pinouto pajungimas).
Tačiau net dvi dienas man niekas neveikė. Nes dokumentacijoje gana miglotai parašyta ir iš pirmo žvilgsnio viskas labai nelogiška. Bėda susijusi su duomenų šynos pločių ir adresu. LCD ekrano A0 pinas, kuris atskiria duomenis nuo komandų prikabintas prie A19 pino. Šio pino lygį turi reguliuoti adresu bitai:

//Musu LCD A0 pajungtas prie A19 pino.
#define LCD_CMD_ADDR 0x60000000
#define LCD_DAT_ADDR 0x60080000

Tačiau niekas neveikė. Pasirodo, mano pavyzdiniam softe buvo ne “unsigned char”, o “unsigned int” (aka uint16). Kituose pavyzdžiuose net 32 bitų kintamasis. Ir dar baisiau- net keletas straipsnių rašė, kad jei naudojam 16 bitų nuskaitymą, adresas pasislenka per vieną bitą, jei 32 bitus, per du bitus. Tačiau ir tai nepadėjo, nes mano pagrindinė klaida buvo tokia, kad nuskaičius 16 bitų iš 8 pin porto, maniau, kad mažesnieji bitai turės reikalingą informaciją. Pasirodo, kad ne. Kiek suprantu, STM čipas hardwariniam lygyje prisiderina prie “bus width” ir dar net kelis nuskaitymus ar rašymus. O jei sukonfiguruota nelogiškai, viskas ir nelogiškai veikia.
Todėl, jei reikia nuskaityti BAITĄ iš 8 laidų šynos, tai reikia C kalboje ir skaityti BAITĄ. Dar nesu tikras ar skaitant WORD iš BYTE nedaromas dvigubas nuskaitymas. Šitą reikia dar patikrinti, nes LCD ekranos softas dar kiek optimizuotusi. O dėl adreso, čia man irgi kiek neaišku, bet baitų, wordų ir longwordų adresai yra atitinkamai pasislinkę, jei norime juos nuskaityti. Pas ARM gal nėra tos bėdos kur yra pas MC68000, kur negalima skaityti pabaičiui ar panašiai iš nelyginių adresų…
Labai daug ir neaiškiai parašiau, bet čia mano “brain dump” ir ši informacija skirta man prisiminti, kaip pajungti FSMC režimą pas STM32F103. Ką dar gero duoda tas FSMC? Ogi DMA.

Kad straipsnis gautusi indomesnis, va fotkė:
LCD

Tai tas didysis ekranas, deja neįjungtas pašvietimas. Naudojamas keistokas “klasikinis” TI99 šriftas kuris gal netinkamas šiam ekranui.

Ir net trys variantai source code su viskuo: mažas ekranas bitbang, didelis ekranas bitbang ir didelis ekranas FSMC:
Husqvarna LCD ir STM32F103 FSMC.

Visas source tikrai neaptvarkyti, yra labai daug eksperimentavimo ir “reverse engineering” likučių.

*) ne visos STM32F103 palaiko FSMC. Čia STM32F103VGT6.

Ta pati plokštė palaiko kelis tipus LCD ekranų su 24 PIN jungtimi (vienas LCD buvo su PE12864URT): PINOUTAS pdf.

Purple pill arba biruolių plokštė

Pamenat, rašiau apie biruolius. Apie kalną STM32F103VBT čipų su kiek palenktom kojom? Tai va, pasidariau eksperimentinę plokštę. Išvedžiau VISAS kojas į 0.1″ kištukus. Dar biški RS485/CAN prielipų pripaišiau tuščioje vietoje.

Purple pill STM32F103VBT
Tikrai sunku prilituoti mikroshemą, kai kojos biški palankstytos. Bet va iš antro karto lygtai ir gavosi. Diagnostinis softas rodo, kad per visas kojytes eina signalai ir trumpų jungimų nėra. Aišku minimalus kiekis detalių ir maitinimas iš “serial debug” lizdo.
Beja, jei netyčia užblokuosit tą “serial wire”, tai nedidelė bėda, užtrumpinat “Reset”, pradeda programuoti ir atjungiat “Reset”.

Užrašai “AL”, “AH”, “EL” ir panašiai, tai pinų grupės. Pvz. AL – PA(0-7), “low” dalis. AH tai PA(8-15) ir t.t.

Visi failai:
Diagnostine firmwarė – source code, STM32Cube failas, kompiliuotas HEX.
Gerberiai – Standartiniai gerberiai, jei staiga užeis noras užsisakyti PCB.
Schema – Šios plokštės schema. Gana negražiai nupaišyta (pdf).
PCB iliustracijos – Šios plokštės PCB vaizdai (pdf).
BOM.

Dėmesio, PCB, bottom pusėje jumperis SJ1 yra jau užtrumpintas į GND. T.y. BOOT0=GND. Jei reikia kitos reikšmės, reikia nupjauti pačiam jumperyje esantį takelį ir prilituoti atitinkamą rezistorių.