1.07.2013

Ethernet na ENC28J60

Długo się przymierzałem do odpalenia sieci na STM32F4Discovery. Na początku nie wiedziałem jakie układy wybrać. Czy iść w stronę MII/RMII czy SPI. Ostatecznie wybrałem SPI czyli coś na układzie ENC28J60. Za tym wyborem przemawia duża liczba publikacji w internecie oraz to, że niektóre płytki do .NET Micro Framework np.: od GHI czy Secret Labs ma interfejsy sieciowe zbudowane na tym układzie. Zaadoptowanie więc rozwiązania do STM32F4Discovery nie powinno być trudne. Jest jeszcze jedna zaleta ENC28J60 jest tani. Gotowy moduł można kupić za około 30 zł. Na początek w sam raz. Ja używam takiego modułu produkcji firmy lcsoft:

ENC28J60 STM32F4Discovery


Sam moduł oczywiście może być inny. Można też samemu zrobić taki interfejs. Ja go po prostu kupiłem.

Kolejnym problemem jest zasilanie. Układ ENC28J60 potrzebuje 3.3V (wg noty katalogowej minimum 3.14V). Na płytce STM32F4 Discovery dostępne mamy tylko 3V i 5V. Trzeba więc użyć zewnętrznego, gotowego zasilacza lub zrobić samemu zasilacz np. tak aby 5V obniżyć do 3.3V. Jeśli mamy zamiar zasilać z 5V to stabilizator powinien być LDO. Ja zrobiłem własny zasilacz na układzie LDO LM1117S według noty katalogowej. Jak to połączyć można zobaczyć na stronie http://fritzing.org/projects/power-3v/.

Kolejnym problemem jest pobór prądu układu ENC28J60. Może on dochodzić do 300mA. Do tego dochodzi jeszcze zasilanie samej płytki STM32F4Discovery. Na przykład przy mruganiu diodami pobiera ona około 40mA. Następne 40mA pobiera część ST-Link/V2 na płytce w stanie spoczynku. W końcu może się okazać, że 500mA z portu USB (maksymalna wydajność dla wersji 2.0) może nie wystarczyć. Port USB 3.0 ma wydajność prądową 900mA więc nie powinno być problemu. Trzeba mieć na uwadze jeszcze to, że wydajność prądowa portu USB może się różnić w zależności od płyty głównej komputera. Jakie jest rozwiązanie? Najprościej użyć zewnętrznego zasilacza do zasilania ENC28J60. Ja poradziłem sobie inaczej. Użyłem dwóch portów USB. Do płytki podłączyłem dwa kabelki USB: do CN1 i CN5. Następnie wyjście PA9 płytki (+5V portu USB CN5) podłączyłem do stabilizatora dla ENC28J60. W taki sposób port CN1 zasila standardowo płytkę, natomiast CN5 zasila moduł ethernet.

No dobra podpinamy moduł ethernet do STM32F4 Discovery. Do tego celu użyłem portu SPI3. Nic jednak nie stoi na przeszkodzie, aby użyć SPI2 (SPI1 nie testowałem). SPI3 ma następujące wyjścia: MSK=PC10, MISO=PC11, MOSI=PC12. Na CS i INT możemy wybrać dowolne, wolne piny np. CS=PA15, a INT=PD1. Wygląda to tak:

ENC28J60 STM32F4Discovery

Jak to uruchomić i się przy tym nie narobić? Z pomocą przychodzi projekt mIP - A C# Managed TCP/IP Stack for .NET Micro Framework. Szkoda tylko, że nie rozwijany. Biblioteka mIP pozwala obsługiwać w prosty sposób ethernet na ENC28J60 bez modyfikacji i kompilacji PK. Nie jest idealna (czasami coś się zacina), ale na razie musi wystarczyć. Do naszego projektu, do referencji, trzeba dodać wcześniej skompilowaną bibliotekę dll lub projekt mIP (NetworkingService i MultiSPI). W źródłach mIP znajdziemy też parę przykładów jak korzystać z biblioteki. Między innymi jak pobrać czas z serwera NTP requestem UDP i prosty serwer http.

Pierwszy kot. Jeśli mamy w sieci serwer DHCP, to będzie bardzo proste. Jeśli DHCP nie mamy to parametry połączenia trzeba ustawić ręcznie (kot znajdziemy w przykładach mIP). Sprawdzamy więc czy wszystko działa:

const SPI.SPI_module spiBus = SPI.SPI_module.SPI3;
const Cpu.Pin chipSelectPin = Stm32F4Discovery.FreePins.PA15;
const Cpu.Pin interruptPin = Stm32F4Discovery.FreePins.PD1;
const string hostname = "stm32f4";
var mac = new byte[] {0x5c, 0x86, 0x4a, 0x00, 0x00, 0xdd};

Adapter.Start(mac, hostname, spiBus, interruptPin, chipSelectPin);
Po uruchomieniu programu w oknie output powinniśmy zobaczyć coś takiego - znaczy wszystko jest ok:

Link is now up :)
Setting IP Address to 10.15.16.109
DHCP SUCCESS! We have an IP Address - 10.15.16.109; Gateway: 10.15.16.1
Updating Gateway Mac from ARP
Done.

W przypadku problemów można zobaczyć bardziej dokładne logi ustawiając przed startem tryb verbose:

Adapter.VerboseDebugging = true;
Adapter.Start(mac, hostname, spiBus, interruptPin, chipSelectPin);

Jak wszystko jest w porządku to "bardziej zaawansowany" przykład. Będziemy pobierać prawdziwą liczbę losową z przedziału 0 do 100 z serwisu www.random.org przez HTTP API.

Aha. Jest pewne ograniczenie w bibliotece mIP. Otóż warstwa TCP może odebrać tylko jeden pakiet (wysyłać może wiele). Więc jeśli odpowiedź przychodzi pofragmentowana to kiszka.

Aha 2. Jest jeszcze jedna sprawa. Aby wykonywać requesty GET ze znakiem ? w url, to trzeba grzebnąć w źródłach mIP. W pliku TCP.cs w linii 556 trzeba wywalić wywołanie funkcji System.Web.HttpUtility.UrlEncode. Czyli linię z:
Path = System.Web.HttpUtility.UrlEncode(url.Substring(Host.Length).Trim(), false);
trzeba zamienić na:
Path = url.Substring(Host.Length).Trim();
No dobra. Teraz już właściwy kot. Jak widać nie jest zbyt skomplikowany:

const SPI.SPI_module spiBus = SPI.SPI_module.SPI3;
const Cpu.Pin chipSelectPin = Stm32F4Discovery.FreePins.PA15;
const Cpu.Pin interruptPin = Stm32F4Discovery.FreePins.PD1;
const string hostname = "stm32f4";
var mac = new byte[] {0x5c, 0x86, 0x4a, 0x00, 0x00, 0xdd};

Adapter.Start(mac, hostname, spiBus, interruptPin, chipSelectPin);

const int minVal = 0;
const int maxVal = 100;

string apiUrl = @"http://www.random.org/integers/?num=1"
    +"&min=" + minVal + "&max=" + maxVal 
    + "&col=1&base=10&format=plain&rnd=new";

var request = new HttpRequest(apiUrl);
request.Headers.Add("Accept", "*/*");

HttpResponse response = request.Send();
if (response != null) 
    Debug.Print("Random number: " + response.Message.Trim());

Brak komentarzy:

Prześlij komentarz