-
1. Data: 2023-07-05 06:54:28
Temat: MCP3208 i mikropyton na RPi Pico
Od: Marcin Debowski <a...@I...zoho.com>
Jakiś czas temu pytałem tutaj o środowisko typu SBC, na którym mógłbym
sobie coś zmajstrować konkretnego i pouczyć pytona. Wtedy wspominałem o
kolorymetrii, ale wyszło cos pilniejszego i obecnie próbuję ogarnąć
obsługę MCP3208 pod ww. RPi (potrzebuje 8-mio kanałowy odczyt
tenperatury). Tzn. zasadniczo mam z lekka ją ogarnietą, ale dla MCP3008.
To zasadniczo wygląda tak, że biblioteka do MCP3008 obsługuje bez
żadnych modyfikacji MCP3208, no ale dostaję wynik 10bit. Czy jakaś dobra
dusza mogłaby mi trochę powyjasniać, bo tu nie tylko że pyton ale
jeszcze programowanie cipa dochodzi? Pytania w kodzie.
Poniżej kod dla mcp3008.py stąd:
https://blog.rareschool.com/2021/02/raspberry-pi-pic
o-project-2-mcp3008.html
import machine
class MCP3008:
def __init__(self, spi, cs, ref_voltage=3.3):
"""
Create MCP3008 instance
Args:
spi: configured SPI bus
cs: pin to use for chip select
ref_voltage: r
"""
self.cs = cs
self.cs.value(1) # ncs on
self._spi = spi
self._out_buf = bytearray(3)
self._out_buf[0] = 0x01
self._in_buf = bytearray(3)
self._ref_voltage = ref_voltage
# co robią te bufory in and out? Rozumiem, że pierwszy bajt coś ustawia,
# a dwa pozostałe są na dane?
def reference_voltage(self) -> float:
"""Returns the MCP3xxx's reference voltage as a float."""
return self._ref_voltage
def read(self, pin, is_differential=False):
"""
read a voltage or voltage difference using the MCP3008.
Args:
pin: the pin to use
is_differential: if true, return the potential difference between two
pins,
Returns:
voltage in range [0, 1023] where 1023 = VREF (3V3)
"""
self.cs.value(0) # select
self._out_buf[1] = ((not is_differential) << 7) | (pin << 4)
self._spi.write_readinto(self._out_buf, self._in_buf)
#kopiuje zawartość out do in?
self.cs.value(1) # turn off
return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]
#tu widzę jakieś przesuwania bitów, ale jak wielkość bufora jest bajt to
#przesunięcie o 8 co daje? A co daje binarne "and" zawartości [1] z
#00000011? Dostaję 2 młodsze bity, które w połączeniu z [2] dają 10
#bitów? Jeśli tak to 0x0F powinno z tego zrobić 12bit a jakby nie rozbi
#- jak podłącze na odpowiedni pin MC3208 3V3 to nadal dostaje 1023, więc
#ta bitowość może jest gdzies definiowana w "machine"?
--
Marcin
-
2. Data: 2023-07-05 12:58:52
Temat: Re: MCP3208 i mikropyton na RPi Pico
Od: "Grzegorz Niemirowski" <g...@g...net>
Marcin Debowski <a...@I...zoho.com> napisał(a):
> self._spi = spi
> self._out_buf = bytearray(3)
> self._out_buf[0] = 0x01
> self._in_buf = bytearray(3)
> self._ref_voltage = ref_voltage
> # co robią te bufory in and out? Rozumiem, że pierwszy bajt coś ustawia,
> # a dwa pozostałe są na dane?
Bufory transmitowane po SPI, jeden na dane do wysłania drugi na dane
odbierane. W nadawczym ustawiana jest wartość pierwszego bajtu. Pierwszy
transmitowany bajt zawiera bit startu i bity kontrolne, które wybierają
kanał oraz określają czy odczyt ma być bezwzględny czy różnicowy. Rozdział 5
w datasheecie.
> self._spi.write_readinto(self._out_buf, self._in_buf)
> #kopiuje zawartość out do in?
Wysyła zawartość out po SPI, odebrane dane umieszcza w in.
> return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]
> #tu widzę jakieś przesuwania bitów, ale jak wielkość bufora jest bajt to
> #przesunięcie o 8 co daje?
Co Cię obchodzi bufor? To nie w nim jest przesunięcie. Odczytywana jest
wartość spod indeksu 1 do tymczasowego miejsca w pamięci i tam jest
przesunięcie. To tymczasowe miejsce zapewne jest co najmniej 16-bitowe.
Bufor nie jest modyfikowany.
> A co daje binarne "and" zawartości [1] z
> #00000011?
Zerowanie starszych 6 bitów, a zachowanie 2 młodszych bez zmian.
> Dostaję 2 młodsze bity, które w połączeniu z [2] dają 10
> #bitów? Jeśli tak to 0x0F powinno z tego zrobić 12bit a jakby nie rozbi
> #- jak podłącze na odpowiedni pin MC3208 3V3 to nadal dostaje 1023, więc
> #ta bitowość może jest gdzies definiowana w "machine"?
Co to jest machine?
MCP3208 zaczyna wysyłać dane nie w określonym miejscu od początku transmisji
SPI, jak to zwykle bywa, ale od momentu bitu startu. Ten bit nie musi być
pierwszym bitem w transmisji. Stąd wychodzi, że to gdzie będą bity danych
jest trochę płynne i zależy od Ciebie. Zobacz sobie obrazek 6-1. Najpierw
przez 5 cykli (bitów) lecą zera, potem bit startu, bit trybu, trzy bity
adresu. Następnie przez 1 bit/cykl nic się nie dzieje. Dopiero potem lecą
dane. Ponieważ bit startu był w tym miejscu w jakim był, dane zaczynają się
od połowy drugiego bajtu.
Zobacz co się dzieje w tym kodzie.
self._out_buf[0] = 0x01
Bit startu jest umieszczony na końcu pierwszego bajtu. Czyli po rozpoczęciu
transmisji leci 7 zer i potem jedynka.
self._out_buf[1] = ((not is_differential) << 7) | (pin << 4)
Bity kontrolne. Na najstarszym miejscu, czyli zaraz po bicie startu, jest
bit trybu. Potem bity kanału.
Czyli wysyłane jest:
0000000S TKKK0000
Układ odpowiada po dwóch cyklach (jeden pusty i jeden zerowy). Czyli co
mamy?
0000000S TKKK0000
00000000 0000P0DD
Czyli w drugim bajcie masz dwa pierwsze bity odpowiedzi. Są to bity 11 i 10.
Co się stało jak poszerzyłeś maskę o dwa bity w lewo? Odczytałeś pusty bit i
zerowy. Cały problem polega na tym, że nie masz czytać wcześniej, ale
później. Masz wziąć dwa bity z bajtu 1, osiem z bajtu 2 oraz DODATKOWO 2
bity z bajtu 3. Tylko, że aktualnie nie masz bajtu o indeksie 3, bo
transmitujesz tylko 3 bajty (indeksy 0 - 2). Musisz wydłużyć transmisję.
Albo zrobić inaczej: wcześniej wysłać bajt startu:
self._out_buf[0] = 0x04 #start
self._out_buf[1] = ((not is_differential) << 1 | (pin >> 2)
self._out_buf[2] = pin << 6
I wtedy odczyt:
return ((self._in_buf[1] & 0x0f) << 8) | self._in_buf[2]
Ogólnie zamieszanie wynika ze stosowania bitu startu, który jest
charakterystyczny dla portu szeregowego. W tym układzie to on wyznacza
początek transmisji a nie opadający /CS. Choć /CS i tak musi najpierw opaść.
Obrazki dobrze to pokazują.
I nie trzeba unikać datasheetu. Lektura karty katalogowej nie gryzie, a
pozwala zaoszczędzić czasu i nerwów.
--
Grzegorz Niemirowski
https://www.grzegorz.net/
-
3. Data: 2023-07-06 05:34:09
Temat: Re: MCP3208 i mikropyton na RPi Pico
Od: Marcin Debowski <a...@I...zoho.com>
On 2023-07-05, Grzegorz Niemirowski <g...@g...net> wrote:
> Albo zrobić inaczej: wcześniej wysłać bajt startu:
> self._out_buf[0] = 0x04 #start
> self._out_buf[1] = ((not is_differential) << 1 | (pin >> 2)
> self._out_buf[2] = pin << 6
> I wtedy odczyt:
> return ((self._in_buf[1] & 0x0f) << 8) | self._in_buf[2]
>
> Ogólnie zamieszanie wynika ze stosowania bitu startu, który jest
> charakterystyczny dla portu szeregowego. W tym układzie to on wyznacza
> początek transmisji a nie opadający /CS. Choć /CS i tak musi najpierw opaść.
> Obrazki dobrze to pokazują.
>
> I nie trzeba unikać datasheetu. Lektura karty katalogowej nie gryzie, a
> pozwala zaoszczędzić czasu i nerwów.
Wielkie dzięki. Muszę to na spokojnie przetrawic i poeksperymentować. I
to nie tak, że unikam datasheetu ale rozmawiasz z osobą, która nigdy w
czymś takim (programowanie ptzrtworników i podobnych) nie robiła, więc
trochę za duża dziura w wiedzy.
--
Marcin