Orange Pi PC Plus SPI vezérlés

 ( diego | 2016. december 28., szerda - 23:13 )

Sziasztok. Van egy hibátlanul működő OrangePi PC Plus, (armbian server image) amin különböző szenzorok vannak. Minden normálisan működik, ezekkel némi guglizás után sikerült zöldágra vergődni. A project része lenne egy PWM-es motorvezérlő is, ebbe viszont beletört a bicskám. A PWM egy áramkör, amivel "lágy indítást" lehet csinálni villanymotorokon, hogy a táp ne szálljon el a kezdeti nagy amper terheléstől. Ennek az áramkörnek a (kézi vezérlésű)potméterének a helyére került bele egy MCP41100-I/P IC, amit SPI interfészen keresztül lehet vezérelni. A terv az lenne, hogy ezen keresztül lehet változtatni a motor fordulatszámát. A PWM panel(plusz az IC) jó, másról vezérelve működik normálisan. Az orangepi tudja ezt kezelni (elvileg) de nekem eddig nem sikerült. Minden vezérlést a WiringOp nevű API-val csináltam, de ez nem akar működni. Néhány napnyi kínlódás után megpróbáltam ugyanezt Python programokkal is, az eredmény ugyanaz. A bekötés jó (pinek: MOSI, SCLK, CL0) ezt többször leellenőriztem. A programok lefutnak hiba nélkül, de ohmban mérhető változás nincs.
Az ls /dev/spi* kimenete:
/dev/spidev0.0
tehát van eszköz. A /sys/class alatt látszik az spi_master is. Az elsődleges gond, hogy az IC csak írható, így nem nagyon lehet ellenőrizni, hogy mi megy ki. A másik gond, hogy minden IC-nek más-más a használata, ezt például 0x11 küldésével lehet fogadásra állítani, más IC-knél ez másképp történik, vagyis az a néhány példa program, ami a neten megtalálható, ezzel az IC-vel nem működik.
Van valaki, akinek sikerült az SPI interfészt működésre bírnia? Tapasztalatok?

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Tegyél be pontos kapcsolási rajz részletet! Az SPI egyszerű, mint a faék, lényegében szinkron soros adatátvitel, egy shift regiszterbe írunk sorosan, majd a végén átírjuk egy latch-be az érkezett adatot.

Amúgy kell ahhoz valami perverz gondolkodás, hogy digitális jelből analógot csináljunk azért, hogy egy digitális áramkört vezéreljünk, amely végül egy analóg perifériát fog vezérelni. :)

Fontos! Ugye betartod, hogy a digitális potenciométered A, B és W termináljai minden időpillanatban GND és VDD közötti potenciálon van, amelyből az is következik, hogy a vezérelt áramkör és ez az IC, de ezáltal az SPI és a hozzá tartozó R-Pi nem lehetnek független potenciálon? Ne feledd, ez nem egy galvanikusan leválasztott potenciométer, nincs benne optocsatoló, hanem egy ellenállás sor, s egy rakás MOSFET, mondhatnám, hogy analóg multiplexer valójában. Sanszos, hogy a terminálokon a GND és VDD lábak felé vannak Clamp-diódák is.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Nagyjából héber amit írtál :-) de az elejéről indulva: Megvolt az Orange, meg a motor relével vezérelve.( Ford Mondeo fűtésmotor, 3 fokozat) Nem volt jó, legnagyobb fordulatszámon indítva levágta a tápot, tehát kell egy PWM. Azt is rendeltem az aliról, de az manuális (100Kohm) potméterrel volt szabályozható... tehát akkor azt is cseréljük ki, ahelyett jött a MCP41100. A poti helyére kerülő nyákot egy kedves elektrotanár ismerősöm készítette, úgy, ahogy a nagykönyvben meg vagyon írva, ő is kihangsúlyozta, hogy külön táp kell a kütyünek. Ő, mikor elkészült, valamivel hardveresen kipróbálta a vezérlést, sőt erről még videót is készített, a motor fordulatszáma szépen változik, a kapott értékek szerint, tehát a PWM panel JÓ.
A gond ott van, hogy hiába kötöm össze az orangepi-vel, semmilyen reakciót nem kapok. Mint írtam, a Wiringop nevű APi-t használom, ez eredetileg a málnához készült, csak portolták az orange-hoz is, eddig minden más szenzort tökéletesen le tudtam vele kezelni. Ebben vannak előre megírt SPI kód minták, (pl max31855, max5322, mcp23s17) tehát kezeli az SPI interfészt, csak én vagyok béna hozzá. Mind a wiringipiben, mind a pythonban írt program hiba nélkül lefut, de nem csinál semmit, magyarán nem változik a fordulatszám.
Ha az segít, szívesen bemásolom ide a programot is, de perpill nem tudom, merre keressem a hibát.
Egy egyszerű python kód, aminek működnie kellene:
#!/usr/bin/env python

#spi_mosi = port:PC00<3>
#spi_miso = port:PC01<3>
#spi_sclk = port:PC02<3>
#spi_cs0 = port:PC03<3><1>

from pyA20.gpio import gpio
from pyA20.gpio import port
from pyA20 import spi

gpio.init()

mosi = port.PC0
sclk = port.PC2
cs0 = port.PC3

gpio.setcfg(mosi, gpio.OUTPUT)
gpio.setcfg(sclk, gpio.OUTPUT)
gpio.setcfg(cs0, gpio.OUTPUT)

spi.open("/dev/spidev0.0")
print "cs0 set 0 \r\n"
gpio.output(cs0, 0)
spi.write([0x11, 0x00]) #Write 2 bytes to slave device
print "cs0 set 1 \r\n"
gpio.output(cs0, 1)
spi.close() #Close SPI bus

Nekem kapcsolási rajzot mutass, de iziben! Az a gyanúm, hogy a vezérelt áramkör és a vezérlés GND-je kóricál egymáshoz képest, szóval rossz a hardware.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Ez nyák rajz, nem kapcsolási rajz. De nem ez az érdekes, hanem az, hogy hogyan van összekötve az R-Pi, az MCP41XXX, meg az a hardware, amit ez a potméter vezérel. Azért érdekes, mert ha a vezérelt hardware felé csak az A, B, W terminálok mennek, az máris rossz.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

erről a PWM-ről van szó:
https://www.aliexpress.com/item/High-Quality-12V-40V-10A-PWM-DC-Motor-Speed-Controller-with-Knob/32737825489.html
A poti helyére került az IC, megpróbálom lefotózni, de úgy látszik, úgy van, ahogy mondod.

Na jó, de hardware-t nem így tervezünk. Tegyük fel - figyelem, gondolatkísérlet! -, ennek a potméternek az egyik vége +12 V-on van, másik vége GND-n. Ezzel két baj van. Az egyik, hogy a digitális potmétered mindegyik terminálja GND és VDD közötti potenciálon lehet, tehát 5 V tápfeszültség esetén legfeljebb 5 V-ra egymástól. A másik, hogy a Clamp-diódákon keresztül megemelheti az MCP tápját, tönkretéve ezzel az IC-t, de mellesleg akár az R-PI tápját is megemelheti, s megy a levesbe az egész gép. Van egy harmadik is, nevezetesen az, hogy a három terminál hiába van egymáshoz képest 5 V-on belül, az MCP GND-je és VDD-je között kell lennie, tehát valahol a GND-vel is össze kell ezeket kötni. Tehát szinte biztos, hogy most rossz a hardware.

Szerk.: Sajnos a nyák rajzról látom, hogy eszetekbe sem jutott az, hogy ez a digitális potméter nem egy lebegő potenciálon lévő valami, hanem a GND-t a PWM-en is valahova kötni kell. Vélhetően a GND-hez, de ne ész nélkül, előbb mérni kell, illetve visszafejteni a PWM kapcsolási rajzát.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Én infós vagyok, nem értek ezekhez :-( Az eredeti PWM-ben 100Kohm-os potméter volt, ugyanilyen értéket tettek a helyére. Hogy a GND most mihez van kötve, én meg nem mondom neked, azt tudom, hogy arra külön felhívták a figyelmem, hogy külön tápról menjen a PWM, és a Orange. Ez így is van, mást ezzel kapcsolatban nem tudok mondani :-(

arra külön felhívták a figyelmem, hogy külön tápról menjen a PWM, és a Orange

Ebben az a legviccesebb, hogy értem miért, bár ez a rossz megoldás. Azért, mert így lesz a legkisebb eséllyel füst, így megy tönkre valami a legkisebb eséllyel, mindeközben úgy, hogy teljesen inkorrekt a megoldás. :(

Szerk.: amúgy szívlapáttal tarkón b.ni, aki ezt így megtervezte...


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

gpio.output(cs0, 0)

Ez elé a sor elé tégy be légy szíves egy ilyet:

gpio.output(cs0, 1)


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Figyelj csak, van még egy gondolatom. Az spi.write() bufferel, vagy nem? Tehát visszatér a függvény, miközben a kernel kiviszi sorosan az adatot, vagy meg is várja, míg az adat kimegy? Ugye tudod, miért kérdem? :)

Ugyanis, ha bufferel, akkor visszatér a függvény, a kernel elkezdi a soros adatot kifelé léptetni, miközben a programod tovább halad, s felrántod a -CS lábat magas szintre úgy, hogy az adat összes bitje még nem lett a shift regiszterbe léptetve. Az ilyen hibás parancsokat pedig abortálja az eszköz, bár, ha nem tenné, akkor sem származna belőle semmi jó.

Szerk.: Az spi.write() hívás után rakj be egy vaskos sleep-et, legyen akár 1 másodperc is a debug kedvéért. Nyilván gány, de arra jó, hogy kiderüljön, mi van.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Jár a szám, mert ráérek, s nézem a katalóguslapját...

Ezt kell tenned.

0) -CS magas szinten van
1) -CS alacsony szintre
2) kiküldesz 0x11-et (MSB first)
3) kiküldöd az adatot (MSB first)
4) -CS magas szintre

Fontos, hogy a két byte küldése között -CS lábat nem emelheted fel magas szintre, mert akkor elabortálja a parancsot. Az órajel felfutásakor vesz mintát az adatból, tehát az órajel felfutása előtt egy setup time-mal (40 ns) korábban már stabilnak kell lennie az adat bitnek, s egy hold time ideig (10 ns) még stabilnak kell maradnia. Az órajel ne legyen 10 MHz-nél gyorsabb.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Igen, a Cs 0, Cs 1 megvan, itt max az írások közti várakozási idővel lehetne játszani, a korábbi verziokban benne volt a sleep(50) de semmit nem használt.

Persze, hogy nem segít, szinkron az átvitel, várhatsz ott egy órát is, akkor ő is vár és bambán néz. ;)


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

A wiringipi forrásában ez az írás függvénye:


/*
* wiringPiSPIDataRW:
* Write and Read a block of data over the SPI bus.
* Note the data ia being read into the transmit buffer, so will
* overwrite it!
* This is also a full-duplex operation.
*********************************************************************************
*/

int wiringPiSPIDataRW (int channel, unsigned char *data, int len)
{
struct spi_ioc_transfer spi ;

channel &= 1 ;

spi.tx_buf = (unsigned long)data ;
spi.rx_buf = (unsigned long)data ;
spi.len = len ;
spi.delay_usecs = spiDelay ;
spi.speed_hz = spiSpeeds [channel] ;
spi.bits_per_word = spiBPW ;

return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ;
}

Tehát én úgy értelmezem, hogy itt megvárja, amig az írásművelet megtörténik, és erről ad egy értéket is. A valóságban a bufferként átadott memóriaterületre írja be a visszatérési értéket.
Kipróbálom a két tippet, a cs0->1 irás előtt, és a sleep-et, hátha...

Ezúttal gyorsabb lenne kipróbálni: egyrészt mielőtt a -CS-t leviszed alacsony szintre, tedd magas szintre. Azért, mert könnyen meglehet, az initben már eleve alacsony szintre kerül, így viszont nem lesz ott egy lefutó él, amely lehet, hogy kell neki. A másik az a sleep, amit mondtam. Egyelőre ne a forrást nézd, ezeket tedd meg, s ha jó, ráérsz szűkíteni a kört arra nézvést, mi az elbökés.

A hardware vonatkozásában legalább azt áruld el, hogy az R-Pi, az MCP41XXX és a vezérelt áramkör GND-je össze van-e kötve, továbbá a vezérelt áramkör a GND-jéhez képest nem akarja-e a potméter bármelyik lábát VDD fölötti vagy GND alatti potenciálon tartani vagy oda kényszeríteni. Ezek nagyon fontos kérdések volnának.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Igekszem, de fotózni is, képet feltölteni, is válaszolni is... Igyekszem :-)
Linkek a nyák hátulról, ez van...
https://drive.google.com/file/d/0B_YAefJ0FujYUHB4cnd1VXFvQU0/view?usp=sharing

A bekötésről a fotó elölről:
https://drive.google.com/file/d/0B_YAefJ0FujYeVg2Wjlla1p0UDg/view?usp=sharing

és ugyanez hátulról:
https://drive.google.com/file/d/0B_YAefJ0FujYUTc5N2RrYm1MVXc/view?usp=sharing

"A hardware vonatkozásában legalább azt áruld el, hogy az R-Pi, az MCP41XXX és a vezérelt áramkör GND-je össze van-e kötve, továbbá a vezérelt áramkör a GND-jéhez képest nem akarja-e a potméter bármelyik lábát VDD fölötti vagy GND alatti potenciálon tartani vagy oda kényszeríteni. Ezek nagyon fontos kérdések volnának."
Érteni értem a kérdést, csak a választ nem tudom... Bocs, én ehhez hüle vagyok. Azért töltöttem fel a nyák fotóját, mert azzal már el tudod dönteni a kérdést, remélem...

Igen, el tudom dönteni. Rossz a hardware. Ettől függetlenül a software-ben is meg kell vizsgálni azokat a dolgokat, amelyekről beszéltünk. Sőt, mondok keményebbet: az is lehet, hogy a software hibák megjavítása után működni kezd, de ettől még rossz marad, ami bármelyik pillanatban tönkre mehet!

A Microchip MCP41XXX katalógus lap második oldalán van az a sor, hogy Resistor Terminals, alatta pedig Voltage Range, a sor végén pedig Note 4, szóval erről beszélek. Az a lényeg, hogy most ezt nem tartod be.

Mindjárt írom, mit kellene csinálni.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Amit én tennék: fognám azt a PWM panelt, s visszafejteném a kapcsolási rajzát, megkeresném a rajta található alkatrészek adatlapjait. Megnézném, az a potenciométer hogyan van bekötve, mekkora feszültségek fordulhatnak elő a GND-hez képest az egyes lábakon. Nem középértékben, hanem időpillanat szerint a szélsőértékek kellenek. Ha ez 0 V és +5 V között van mindhárom lábra, akkor pezsgőt bontanék, s egyszerűen összekötném a PWM GND-jét az MCP41XXX és egyben az R-Pi GND-jével, majd boldogan élnék, míg meg nem halnék.

Aztán van az a lehetőség, hogy az egyes lábak messzebbre kerülnek 5 V-nál a GND-től. Ekkor megvizsgálnám, hogyan lehetne a PWM-et áttervezni úgy, hogy a kívánt állapot álljon elő. Ha ez sem megy, terveznék saját PWM-et. Amúgy nevetni fogsz, ez utóbbi a legolcsóbb, legegyszerűbb dolog talán. Miért?

Azért, mert vannak mikrokontrollerek - például épp a Microchip egyes 8 bites MCU-i - amelyeknek van SPI interface-e, s egyben van PWM kimenete is. Erre nyilván kell firmware-t írni, nagy dolog. A húzósabb a végfok, de power MOSFET-et lehet kapni a boltban, induktivitást is, Schottky-diódát is, meg FET meghajtó IC-t is.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Közben kipróbáltam az írás előtti magas szintet (cs0->1, majd utána cs0->0, SPI_write, cs0->1) Ez sajna nem vált be, sem sleep-el sem anélkül.
A GND megvan az orange és az MCP411xx között, hisz onnan kapja a +5V-t meg a GND-t, de hogy ehhez a PWM GND-je hogy viszonyul...
Mindenesetre nagyon köszönöm, hogy próbáltál segíteni, előbb utóbb csak sikerül :-)

Mindenképp mérj előbb! Ha ugyanis összekötöd a PWM GND-jét az MCP és így az R-Pi GND-jével, akkor ugyanazt teszed, mintha közös tápról járnának, ami műszakilag ugyan szükséges lenne, de csak akkor, ha a feszültségre vonatkozó követelmények teljesülnek. Ellenkező esetben füst lehet a vége.

Örömmel segítenék, csak ezt így távolról már nehéz, de érdekel a folytatás.

Az a baj, hogy az az MCP41100 már lehet, hogy rég döglött. Nem így kellett volna ezt jól csinálni. Lehet digitális potméterrel, de vagy saját tervezésű hardware-ben, vagy legalább ismert hardware-ben, ha teljesülnek a feltételek, vagy átalakítjuk úgy, hogy teljesüljenek.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Azért majd jelezd, ha jutottál valamire, legyen az bármi is. Érdekel.


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Megoldódott, Működik! A bootolásnál betöltött flex volt hibás, a CS láb konfigja volt a hunyó, fixen 1-es módba volt állítva (de miért?)
Alapértelmezett módba állítva már az első próbálkozás is sikeres volt.

Az 1-es mód mit jelent? Bemenetként volt programozva, így nagy impedanciás volt?


tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Nemcsak azt szabja meg, hogy a pin milyen állapotban van(in/out/clock/pwm...stb) hanem azt is, hogy melyik regiszterhez kapcsolódik (bocs, ha nem vagyok szakszerű)
Itt a specifikáció, igy megérted:
Allwinner H3 Datasheet
Keresd a 74. oldal környékén a GPIO Multiplexing Functions táblázatot, Pin name: PC0-PC05 részt

sub