PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Raspi C/C++, Raspi als I2C-Master: byte arrays zu Arduino slave hin + her schicken?



HaWe
03.02.2016, 19:29
hallo,
hat oder kennt hier jemand funktionierenden Code in C für den Raspi, um via I2C einen Arduino als Multiplexer Board zu nutzen?
Es müssen vom Raspi als Master nur "rohe" byte arrays (Größe bis 30 bytes) auf den Arduino übertragen (abwechselnd geschrieben/gelesen) werden.

Per UART habe ich es problemlos hinbekommen (sowohl Arduino/Arduino als auch Raspi/Arduino),
und per I2C klappt auch Arduino zu Arduino einwandfrei.
Auch Auslesen eines I2C Sensors (CMPS11) klappt wunderbar mit dem Raspi, und ntl auch mit dem Arduino.

Nur leider scheitert es mit Raspi als i2c-Master zum Arduino, und mir fehlen leider die C- und device tree- Kenntnisse für den Raspi, um das umzusetzen. So schöne einfache Dinge wie
Wire.requestFrom(address, count)
Wire.beginTransmission(address)
Wire.endTransmission()
Wire.send()
Wire.available()
Wire.receive()
Wire.onReceive(handler)
Wire.onRequest(handler)
etc. gibt es ja beim Raspi nicht.

Hat oder kennt wer fertigen Code, den ich dafür verwenden könnte?


edit:
dies ist der Arduino Slave code, der ansonsten gut mit dem entsprechenden Arduino-Master-Code zusammen funktioniert
- jetzt soll ein passender Raspi-Master-Code her:


// Arduino code to send/receive byte arrays
// Arduino as an I2C slave
// compiles for MEGA and DUE, IDE 1.6.5
// ver. 0.001


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
#define MSGSIZE 30
byte recvarray[MSGSIZE]; // 0=0xff; 1=chksum; ...data...; MSGSIZE-1=SLAVE_ADDRESS
byte sendarray[MSGSIZE];

volatile int8_t flag=0;


//================================================== ===================================
//================================================== ===================================
void setup() {
int32_t i=0;

// Serial terminal window
i=115200;
Serial.begin(i);
Serial.print("Serial started, baud=");
Serial.println(i);

// Wire (i2c)
Wire.begin(SLAVE_ADDRESS); // start Arduino as a I2C slave, addr=0x04 (7-bit coded)

Wire.onReceive(receiveData ); // event when master array is sent
Wire.onRequest(sendData ); // event when master requests array to read

memset(sendarray, 0, sizeof(sendarray) ); // init send- and recv arrays
memset(recvarray, 0, sizeof(recvarray) );

Serial.print("I2C init: my slave address= ");
Serial.println(SLAVE_ADDRESS);
Serial.println("I2C init: done.");
Serial.println();

Serial.println("setup(): done.");

}


//================================================== ===================================


uint8_t calcchecksum(uint8_t array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}

//================================================== ===================================

void loop()
{
char sbuf[128];

Serial.println(); Serial.println();

// do something with the received data
// and then do something to build the sendarray [3]...[MSG_SIZE-2]

sendarray[0] = 0xff; // 0 = start: 0xff == msg start flag
sendarray[2] = flag; // 2 = send back msg error flag
sendarray[MSGSIZE-1] = SLAVE_ADDRESS; // end of array: ID check
sendarray[1] = calcchecksum(sendarray); // 1 = calc new chksum
flag=0;

// debug output
sprintf(sbuf, "Sendarr[4]=%4d, [5]=%4d, Recvarr[4]=%4d, [5]=%4d",
sendarray[4], sendarray[5], recvarray[4], recvarray[5]) ;
Serial.println(sbuf);

delay(2); // short break for the cpu and the bus
}


//================================================== ===================================

void receiveData(int byteCount) {
int32_t i;
byte val;

while(Wire.available()<MSGSIZE) ; // wait for all bytes to complete
i=0; // init counter var
while(Wire.available()&& (i<MSGSIZE) ) // read all recv array bytes
{
val=Wire.read();
recvarray[i++]=val;
}

// check for transmission error
if( (recvarray[0] == 0xff)
&& (recvarray[1] == calcchecksum(recvarray))
&& (recvarray[MSGSIZE-1] == SLAVE_ADDRESS ) )
flag=1; // data ok
else
flag=127; // data faulty => handle rcv-error => flag =127
}

//================================================== ===================================

void sendData(){
// Wire.write writes data from a slave device in response to a request from a master
Wire.write(sendarray, MSGSIZE); // send own byte array back to master..
}


//================================================== ===================================

m.a.r.v.i.n
05.02.2016, 09:20
Hallo HaWe,
WiringPi unterstützt auch I2C. https://projects.drogon.net/raspberry-pi/wiringpi/i2c-library/ . Damit sollte es klappen.

HaWe
05.02.2016, 09:34
ja, aber ich kriege keinen Code für die array- Kommunikation zum Arduino hin, weder mit dem normalen read() noch mit den WiringPi Funktionen
wiringPiI2CReadReg8(addr, reg)
denn der Arduino hat ja keine Register.
normales wiederholtes read() liest aber immer nur das 1. array-byte aus (also array[0]), der Arduino incrementiert seinen Zähler (Lese-Buffer-Pointer) nicht.

edit: einzelne Bytes schreiben + lesen funktioniert! Nur array-Zellen nacheinander auslesen nicht!

Wird er von einem anderen Arduino als Master mit Wire.requestFrom(address, count) etc. wiederholt ausgelesen, dann liest er alle array nacheinander aus, so wie es sein soll.

Selbst Gordon Henderson hat aber bisher mit seiner eigenen Lib und Arduino-IDE-programmiereten Arduinos keine als slaves auslesen können/wollen - nur mit bare-metal-programmierten AVRs hat er es schon mal gemacht (also ohne die Arduino-Wire-Class).

"...damit [I]sollte es klappen" führt hier offenbar nicht weiter: Höchstwahrscheinlich ist wiringPi dafür eine Sackgasse.

Daher brauche ich jemanden, der mir einen Code vorschlagen kann, der tatsächlich mit arrays zwischen Raspi und Arduino (Wire) funktioniert.

m.a.r.v.i.n
05.02.2016, 13:24
Hast du mal so etwas probiert?


unsigned char rcvbuff[30];
int fd = wiringPiI2CSetup(0x04);
read(fd, rcvbuff, 30);
close(fd);

und zum senden:


unsigned char sndbuff[30];
int fd = wiringPiI2CSetup(0x04);
write(fd, sndbuff, 30);
close(fd);

HaWe
05.02.2016, 15:08
ich habe diesen Code probiert von http://blog.retep.org/2014/02/15/connecting-an-arduino-to-a-raspberry-pi-using-i2c/



#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-1";

int main(int argc, char** argv) {

if (argc == 1) {
printf("Supply one or more commands to send to the Arduino\n");
exit(1);
}

printf("I2C: Connecting\n");
int file;

if ((file = open(devName, O_RDWR)) < 0) {
fprintf(stderr, "I2C: Failed to access %d\n", devName);
//fprintf( stderr, “I2C: Failed to access %s : %s\nâ€, devName, strerror (errno) );
exit(1);
}

printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
exit(1);
}

int arg;

for (arg = 1; arg < argc; arg++) {
int val;
unsigned char cmd[16];

if (0 == sscanf(argv[arg], "%d", &val)) {
fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
exit(1);
}

printf("Sending %d\n", val);

cmd[0] = val;
if (write(file, cmd, 1) == 1) {

// As we are not talking to direct hardware but a microcontroller we
// need to wait a short while so that it can respond.
//
// 1ms seems to be enough but it depends on what workload it has
usleep(10000);

char buf[1];
if (read(file, buf, 1) == 1) {
int temp = (int) buf[0];
printf("Received %d\n", temp);
}
}

// Now wait else you could crash the arduino by sending requests too fast
usleep(10000);
}

close(file);
return (EXIT_SUCCESS);
}


und den Teil

char buf[1];
if (read(file, buf, 1) == 1) {
int temp = (int) buf[0];
printf("Received %d\n", temp);
}

geändert in


char buf[30];
if (read(file, buf, 30) == 1) {
for (int j = 0; j<30; ++j) {
temp=buf[j];
printf("Received %d\n", temp);
}
}

aber er liest hier nur 30x das erste byte in array[0] und nicht den Rest des arrays.

Ich denke auch, es macht keinen Sinn an diesem beispiel rumzudoktern, man braucht völlig neu aufgesetzten Raspi- Code zum abwechselnen wiederholten array- schreiben und lesen.

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

morob
05.02.2016, 15:13
for (int j = 0; j<30; j++) {

HaWe
05.02.2016, 15:58
for (int j = 0; j<30; j++)
ja, klar, daran liegt es nicht, das war ein typo und war hier nur blind eingefügt gewesen.

ansonsten, wie gesagt,

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

HaWe
05.02.2016, 22:27
update:
habe jetzt einen ersten Testcode als Arbeitsgrundlage: mein eigener Arduino Slave code und ein zusätzlicher Raspi Master code (eine einfache Raspi-Mustervorlage dafür hatte Gordon Henderson gepostet und wurde entsprechend angepasst) - ist aber noch extrem langsam und muss noch dringend schneller gemacht werden:

http://www.mindstormsforum.de/viewtopic.php?f=78&t=8689&start=15#p67908


Verbesserungs- und Beschleunigungs-Tipps von Raspi-Profis werden gern entgegengenommen!

Peter(TOO)
06.02.2016, 06:10
Hallo,

for (int j = 0; j<30; j++) {

++j und j++

Sind hier identisch: j = j+1

Unterschiede gibt es, wenn j verwendet wird.
c[j++] --> c[j]; j=j+1;
c[++j] --> c[j+1]; j=j+1;

a = c[--i]; und c[i++] = a; können eigentlich alle CPUs als jeweils einzelnen Assembler-Befehl ausführen (PUSH und POP). Manchmal auch als a = c[i--]; und c[++i] = a; implementiert.
Bei manchen CPUs beschränkt sich diese Adressierungsart nicht nur auf den Stack und kann auch symmetrisch sein.

MfG Peter(TOO)

HaWe
06.02.2016, 11:01
danke, aber was soll das jetzt? Die Frage war nicht nach pre- oder post-increment, das ist mir sonnenklar, sondern nach einem Code, der eine schnelle i2c Verbindung zwischen Raspi-Master und Arduino-Slave herstellt.
Ausgangsbasis kann der obige Code im oben verlinkten Post sein
- immerhin gibt es ja inzwischen einen, der zumindest funktioniert, wenn auch extremst langsam - :
http://www.mindstormsforum.de/viewtopic.php?f=78&t=8689&start=15#p67908

aber wenn Vorschläge, dann bitte selbst getestet: es ist das exakte Zusammenspiel der beiden i2c-Protokolle, das Probleme macht!
(Und bitte erst recht keine OT-Posts.)

Denn, wie gesagt:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

Peter(TOO)
06.02.2016, 12:12
Hallo,

danke, aber was soll das jetzt? Die Frage war nicht nach pre- oder post-increment, das ist mir sonnenklar, ....
Das war ja auch nicht für dich, sondern gegen den Einwand von Morob.

MfG Peter(TOO)

HaWe
06.02.2016, 12:20
macht das doch bitte per PM aus! solche OT posts sprengen ständig den Informationsfluss!

also nochmal:

Die Frage war nach einem Code, der eine schnelle i2c Verbindung zwischen Raspi-Master und Arduino-Slave herstellt.
Ausgangsbasis kann der obige Code im oben verlinkten Post sein
- immerhin gibt es ja inzwischen einen, der zumindest funktioniert, wenn auch extremst langsam - :
http://www.mindstormsforum.de/viewtopic.php?f=78&t=8689&start=15#p67908

aber wenn Vorschläge, dann bitte selbst getestet: es ist das exakte Zusammenspiel der beiden i2c-Protokolle, das Probleme macht!
(Und bitte erst recht keine OT-Posts.)

Denn, wie gesagt:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

HaWe
06.02.2016, 15:16
hmmm.... scheint, als gäbe es hier im Forum keine wirklichen Fachleute für i2c zwischen Raspi und Arduino.... :-/

peterfido
06.02.2016, 16:36
Hallo,

wenn das Beispiel zu langsam ist, würde ich die Pausen verkürzen. Aus sleep(1) usleep(100), aus delay(2) delay(1), oder beim Senden vom ARDUINO ganz auf das delay verzichten.

HaWe
06.02.2016, 17:10
wie gesagt:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

Augenblicklich überträgt der Raspi-Master zum Arduino und zurück gerade mal 2 arrays pro Sekunde (!!), per Arduino-Master ist das gleiche Programm > 30x so schnell. Da wird eine Verkürzung um ein paar millis oder micros nichts ausmachen.
Es liegt vielmehr am Zusammenspiel der beiden i2c-Implementierungen, dem langsamen Arduino und dem prinzipiell schnelleren Raspi, der aber clock-stretching nicht verträgt - damit bricht die Kommunikation ein. Außerdem braucht der Arduino ZWINGEND delays, um überhaupt auf requests reagieren zu können. Die Sache ist also recht kniffelig.

Nicht umsonst habe ich daher oben geschrieben:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

vermutlich hast du deinen Vorschlag also nicht getestet...?

peterfido
06.02.2016, 19:02
Nein,
aber ich bin in der Lage dazu, da ich die Voraussetzungen alle erfülle ;) Für ein Nachstellen der Situation fehlt mir an diesem WE die Zeit. Ich komm leider nicht mal dazu, an meinem eigenen aktuellen Projekt zu programmieren ;)

Eine 1a Kommunikation zwischen Raspi und AVR klappt per UART. Hier laufen 5 solcher Paare schon eine Zeit lang.

I2C zwischen Raspi und Display sowie ARDUINO und Display läuft bei mir gefühlt verzögerungsfrei. I2C zwischen Raspi und ARDUINO habe ich wegen UART noch nicht gebraucht. Muss es unbedingt I2C sein, wo Clock Stretching, welches dem Raspi zu schaffen macht, wahrscheinlich ist? Und wenn ja, hängen da noch weitere Geräte auf dem Bus? Clock Stretching ist beim Raspi problematisch. Entweder gleich vermeiden, z.B. durch einen langsameren I2C Takt (http://doc.byvac.com/index.php5?title=RPI_I2C)oder I2C zu Fuß per Bit Banging nachbauen. Erfolge soll es auch geben, wenn dem AVR Rechenzeit durch Verzögerung der Read-Ack verschafft wird.

Was, wenn der Raspi erst einen Befehl sendet, dass der ARDUINO weiß, dass er Daten zum Senden parat haben muss, das Lesen der Daten in einer bestimmten Zeit x passiert?

Auf einer Raspi-Zusatzplatine, deren Name mir gerade nicht einfällt, wird das Problem durch einen zusätzlichen Mikrocontroller als I2C -Proxy umgangen.

HaWe
06.02.2016, 19:42
UART funktioniert perfekt, sogar drahtlos - aber der Raspi hat nur 1 UART, USB ist besetzt, aber viel wichtiger: UART kann nur 1 "slave", i2c aber über 100...
Und UART wird für eine Drahtlos-Fernsteuerung benutzt... (2x HC-05: was war das für eine Höllenqual, bis ich die endlich zum Laufen hatte!)

Ich hab zwar nun keine 100 slaves, aber 2 Arduinos (1x Due, 1x Mega) plus GPS plus IMU plus RTC .... (auch über eine Pixy cam bin ich jetzt wieder gestolpert).
Wenn es also schnell genug ginge, könnten alle an 1 i2c-1, notfalls ein Teil davon an i2c-0.

Wenn du also testen kannst - ich bin gespannt! (y) +1 8-)

HaWe
07.02.2016, 11:11
hmmm ...
aber sonst scheinen keine weiteren Raspi- und Arduino-Fachleute hier an Bord zu sein, die zufällig außer Ahnung auch noch Zeit haben, sich mitzuteilen?
;)

peterfido
07.02.2016, 14:57
Hallo,

ich habe mal kurz Zeit gefunden. Das Setup steht soweit. Der Raspi findet den ARDUINO. Von Vorteil wären Deine aktuellen Testprogramme für beide Plattformen. Das, welches Du weiter oben als Basis verlinkt hast, macht von Haus aus schon 120ms Pause jeden Loop. Warum der State auf dem ARDUINO zwischengespeichert wird, habe ich noch nicht verstanden. Das Testprogramm für den Raspi möchte ja die zu sendenden Daten mit übergeben haben. Wird also nicht das sein, womit Du testest.

Meine Pegelwandler sind alle. Habe mir eben welche geordert. Wenn die da sind, teste ich weiter. Der ARDUINO läuft zwar mit 3V3 aber den muss ich sonst vor und nach dem Flashen umstecken. Wenn ich das vergesse, kann es das für den Raspi gewesen sein.

HaWe
07.02.2016, 19:19
120ms Pause ?
wo?
hast du diesen Code hier von diesem Link?

http://www.mindstormsforum.de/viewtopic.php?f=78&t=8689&start=15#p67908

der Raspi-Teil stammt von Gordon Henderson -
Frage:
was macht sleep(1)? 1 ms ? oder etwa 1sec ?


ps
(edit: )
Ja, du hast Recht!

Der Raspi hat eingebaute Pullups, die auf 3.3V hochziehen, aber beim Mega verbleiben 10k Board-Pullups, die machen es grenzwertig, auch wenn man die internen disabled. Tatsächlich sind beim mega Levelshifter sicherer!


- - - Aktualisiert - - -

hahaha, das war's!

Gordon hatte 1 sek Wartezeit drin, nicht 1 ms!

ich hab jetzt auf delay(10) geändert - das rauscht nur so durch, dass man gar nicht hinterher kommt !!

das muss ich mir jetzt erstmal genauer angucken!

- - - Aktualisiert - - -

update:

schaut absolut grandios aus. Kein Transmission-Fehler erkennbar. Mal gucken, wie lang die i2c Verbindung hält oder ob sie abbricht:

Raspi Master Code:


// Raspberry Pi Master code to send/receive byte arrays
// to an Arduino as an I2C slave
//
// ver. 0.001b
// protected under the friendly Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// http://creativecommons.org/licenses/by-nc-sa/3.0/ //

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#include <errno.h>
#include <string.h>

#define MSGSIZE 30


unsigned char calcchecksum( unsigned char array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}



int main (void)
{

int fd, i ;
unsigned char test=0;
unsigned char data [MSGSIZE] ;

if ((fd = wiringPiI2CSetup (0x04) ) < 0)
{
fprintf (stderr, "Can't open RTC: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}


for (;;)
{
read (fd, data, MSGSIZE) ;
if( data[1] != calcchecksum( data ) ) {
// handle transmission error !
}
printf ("read: ");
for (i = 0 ; i < MSGSIZE ; ++i)
printf (" %3d", data [i]) ;
printf ("\n") ;
delay(10);

memset(data, 0, sizeof(data) );
data[5]= test++;
data[0]= 0xff;
data[MSGSIZE-1]= 0x04;
data[1] = calcchecksum( data );

write(fd, data, MSGSIZE) ;
printf ("write: ");
for (i = 0 ; i < MSGSIZE ; ++i)
printf (" %3d", data [i]) ;
printf ("\n\n") ;
delay(10);
}

return 0 ;
}


Arduino slave code


// Arduino code to send/receive byte arrays
// Arduino as an I2C slave
// compiles for MEGA and DUE, IDE 1.6.5
// ver. 0.001b
// (c) HaWe 2016
//
// protected under the friendly Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// http://creativecommons.org/licenses/by-nc-sa/3.0/ //


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
#define MSGSIZE 30
byte recvarray[MSGSIZE]; // 0=0xff; 1=chksum; ...data...; MSGSIZE-1=SLAVE_ADDRESS
byte sendarray[MSGSIZE];

volatile int8_t flag=0;


//================================================== ===================================
//================================================== ===================================
void setup() {
int32_t i=0;

// Serial terminal window
i=115200;
Serial.begin(i);
Serial.print("Serial started, baud=");
Serial.println(i);

// Wire (i2c)
Wire.begin(SLAVE_ADDRESS); // start Arduino as a I2C slave, addr=0x04 (7-bit coded)

Wire.onReceive(receiveData ); // event when master array is sent
Wire.onRequest(sendData ); // event when master requests array to read

memset(sendarray, 0, sizeof(sendarray) ); // init send- and recv arrays
memset(recvarray, 0, sizeof(recvarray) );

Serial.print("I2C init: my slave address= ");
Serial.println(SLAVE_ADDRESS);
Serial.println("I2C init: done.");
Serial.println();

Serial.println("setup(): done.");

}


//================================================== ===================================


uint8_t calcchecksum(uint8_t array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}

//================================================== ===================================

void loop()
{
char sbuf[128];

Serial.println(); Serial.println();

// do something with the received data
// and then do something to build the sendarray [3]...[MSG_SIZE-2]

if (flag==1) {
//debug
sendarray[4] +=1;
}

sendarray[0] = 0xff; // 0 = start: 0xff == msg start flag
sendarray[2] = flag; // 2 = send back msg error flag
sendarray[MSGSIZE-1] = SLAVE_ADDRESS; // end of array: ID check

sendarray[1] = calcchecksum(sendarray); // 1 = calc new chksum
flag=0;

// debug output
sprintf(sbuf, "Sendarr[4]=%4d, [5]=%4d, Recvarr[4]=%4d, [5]=%4d",
sendarray[4], sendarray[5], recvarray[4], recvarray[5]) ;
Serial.println(sbuf);

delay(1); // short break for the cpu and the bus
}


//================================================== ===================================

void receiveData(int byteCount) {
int32_t i;
byte val;

while(Wire.available()<MSGSIZE) ; // wait for all bytes to complete
i=0; // init counter var
while(Wire.available()&& (i<MSGSIZE) ) // read all recv array bytes
{
val=Wire.read();
recvarray[i++]=val;
}

// check for transmission error
if( (recvarray[0] == 0xff)
&& (recvarray[1] == calcchecksum(recvarray))
&& (recvarray[MSGSIZE-1] == SLAVE_ADDRESS ) )
flag=1; // data ok
else
flag=127; // data faulty => handle rcv-error => flag =127
}

//================================================== ===================================

void sendData(){
// Wire.write writes data from a slave device in response to a request from a master
Wire.write(sendarray, MSGSIZE); // send own byte array back to master..
}



- - - Aktualisiert - - -

also, es läuft jetzt störungsfrei seit etwa ner halben Stunde - da gibt's momentan nichts mehr zu meckern!

(y)

peterfido
08.02.2016, 15:17
Hallo,

prima, dann brauch ich nicht weiter testen. Mache es am WE trotzdem mal ;)

Edit:
SDA ist bei meinem ARDUINO auf High, wenn ich Deinen Code compiliere. Daher die Pegelandler oder den Mega2560 mit 3V3 betreiben.

HaWe
08.02.2016, 15:52
Beim Mega muss man zwingend die dort vorhandenen internen Pullups auf 5V disablen; dazu 2 Zeilen in twi.c auskommentieren:

file: twi.c ( path: Arduino\hardware\arduino\avr\libraries\Wire\utilit y )
// activate internal pullups for twi.
// digitalWrite(SDA, 1);
// digitalWrite(SCL, 1);

ps
(edit: )
Ja, du hast Recht!

Der Raspi hat eingebaute Pullups, die auf 3.3V hochziehen, aber beim Mega verbleiben 10k Board-Pullups, die machen es grenzwertig, auch wenn man die internen disabled. Tatsächlich sind beim mega Levelshifter sicherer!

peterfido
08.02.2016, 18:11
Hallo,

ich habe es auskommentiert. Die Pullups sind aber immer noch aktiviert. Evtl. was auf dem Board.?. Meiner ist von Sainsmart, MEGA2560. Suche ich morgen weiter, jetzt kommt Wheelers Dealers :)

Dein Programm läuft soweit, bis man kurz mal die Verbindung trennt. Dann syncen die nicht mehr auf Beginn des Telegramms. Auch das werde ich mir mal näher ansehen.

HaWe
08.02.2016, 20:23
Hm - bisher habe ich nur den Due beutzt - aber ja, tatsächlich, er hat 2 im Prozessor und 2 auf dem Board. Die einen lassen sich disablen, die anderen nicht.
Angeblich sollen aber die verbleibenden wegen Ihres höheren Widerstandes dann nicht mehr ins Gewicht fallen :
http://www.varesano.net/blog/fabio/how-disable-internal-arduino-atmega-pullups-sda-and-scl-i2c-bus

internal pullups
Submitted by as3.1415rin (not verified) on Thu, 2012-07-19 21:39.

as far as I understand, the 5V/3.3V is the only reason to switch them off. if that's not the point, internal + external pullups should be fine, then the activated internal ones are not doing any damage


ps
(edit: )
Ja, du hast Recht!

Der Raspi hat eingebaute Pullups, die auf 3.3V hochziehen, aber beim Mega verbleiben 10k Board-Pullups, die machen es grenzwertig, auch wenn man die internen disabled. Tatsächlich sind beim mega Levelshifter sicherer!


ps,
das mit dem re-syncen stimmt und ist noch nicht gelöst. Ich war jetzt nach dem sleep-Bug erstmal froh, dass es überhaupt schon sehr schnell lief. Ich weiß auch nicht, wie es sonst auf dem Raspi läuft, wenn mal eine i2c-line zu einem Device wie z.B. einem MCP oder PCF zwischenzeitlich ausfällt und dann wieder hergestellt wird. Ein stabiles Protokoll mit re-sync wäre schon wünschenswert. Eventuell könnte man einen Timer mitlaufen lassen, der z.B. nach 100ms time-out sowohl auf dem Master als auch dem Slave i2c resettet und dann neu startet?

HaWe
09.02.2016, 08:41
habe jetzt genauere Infos aus dem Arduino-Forum:

On the Arduino Mega 2560 board are pullup resistors of 10k for SDA and SCL. The internal pullup resistors of the ATmega2560 chip are about 50k.

The internal pullup resistors can be disabled in the library, or in the sketch.
It can be done in the sketch, because SDA and SCL are still digital inputs, even if I2C is enabled for those pins. So writing a zero disables the pullup.
Code: [Select]


Wire.begin();
digitalWrite( SDA, LOW);
digitalWrite( SCL, LOW);

...


It is the other way around.
The 50k are internal in the ATmega2560 chip and can be disabled.
The 10k are on the Arduino Mega 2560 board and can not be disabled. Perhaps you can try to scratch a pcb trace and work around that 10k.

The Arduino Mega 2560 is the only board with those 10k resistors on the board for I2C. Any other board would be no problem.

Connect 5V with 10k to 3.3V with 1k8. That makes 3.55V
I don't like that, often 3.6V is the limit for 3.3V chips, and this is very close.

Using a dirty trick with a resistor to GND to lower it might also cause trouble. The Arduino Mega board needs 3.5V to see a I2C level as high.

With a level shifter, the Arduino has to pull both sides of the level shifter down. A level shifter has often 10k on both sides.
Total current:
5V with 10k and 10k : 1mA
3.3V with 1k8 and 10k : 2.16mA
Together it is above 3mA, which is specified as the maximum current by the official I2C standard. But that 3mA is not very strict, it will work :)
http://gammon.com.au/forum/?id=10896&reply=5#reply5

My conclusion : Use a level shifter or an other Arduino board.

Also, ich muss mich berichtigen: gerade die blöden 10k lassen sich nicht disablen, und damlt wird es tatsächlich kritisch.

peterfido
09.02.2016, 15:00
Hallo,

ja, ich werde auf die Pullups warten. Die sollten demnächst eintrudeln.

Wenn die stören, opfere ich ein USB-Kabel und führe die 5V über eine 3V3 Regelplatine zum ARDUINO.

Das Protokoll habe ich gestern schon bissel bearbeitet, ist aber noch nicht fertig. Zumindest klappt die Sync noch nicht.

Edit:
Danke für die Recherche mit den Pullups. Da sich ein Raspi vor einiger Zeit schon verabschiedet hat, messe ich jetzt immer doppelt und dreifach, bevor ich was verbinde ;)

HaWe
09.02.2016, 15:06
klasse, wär ja super, wenn wir da was gemeinsam auf die Beine stellen könnten.
Ich hab gestern abend/nacht schon einen älteren Levelshifter bei mir probiert, damit gings nicht. ich hab aber noch einen neueren, ungebrauchten, mal gucken, was der sagt.
heute abend weiß ich mehr...

ps:
wie man i2c buffer_size beim Arduino vergrößert, weiß ich zwar, aber nicht wie's beim Raspi geht.
64 bytes wären schön auf beiden Seiten, dann kann man sogar jede menge long-int Encoder-Werte oder floats übertragen...

Haste du da evtl auch ne Idee?

HaWe
09.02.2016, 20:01
klappt bei mir nicht mit Mega und Levelshifter:
für die ersten 10 bis 30 Arrays werden vom Slave Daten ausgetauscht, dann passiert am Mega plötzlich nichts mehr;
auch der Raspi kriegt keine neuen Daten mehr: i2c tot.

i2cdetect -y l zeigt anschließend keinen i2c-slave mehr an 0x04 an.


pi@raspberrypi ~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Jetzt hab ich noch einen 3. Levelshifter gefunden, da sind aber noch keine Pins dran....: morgen also....


Der Raspi-Code muss übrigens noch etwas abgeändert werden, dass er nur dann seine Test-Variable weiterzählt, wenn er vorher einen korrekten Array vom Slave bekommen hat - er ist jetzt schon besser, aber noch nicht 100% ok:



// Raspberry Pi Master code to send/receive byte arrays
// to an Arduino as an I2C slave
//
// ver. 0.002
//
// protected under the friendly Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// http://creativecommons.org/licenses/by-nc-sa/3.0/ //

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#include <errno.h>
#include <string.h>

#define MSGSIZE 30


unsigned char calcchecksum( unsigned char array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}



int main (void)
{

int fd, i ;
unsigned char test=0;
unsigned char data [MSGSIZE] ;

if ((fd = wiringPiI2CSetup (0x04) ) < 0)
{
fprintf (stderr, "Can't open RTC: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}


for (;;)
{
memset(data, 0, sizeof(data) );
data[0]= 0xff; // init for transmission error check
read (fd, data, MSGSIZE) ;
if( data[1] != calcchecksum( data ) ) {
// handle transmission error !
}
else {
printf ("read: ");
for (i = 0 ; i < MSGSIZE ; ++i)
printf (" %3d", data [i]) ;
printf ("\n") ;
delay(10) ;

memset(data, 0, sizeof(data) );
data[5]= test++;
data[0]= 0xff;
data[MSGSIZE-1]= 0x04;
data[1] = calcchecksum( data );

write(fd, data, MSGSIZE) ;
printf ("write: ");
for (i = 0 ; i < MSGSIZE ; ++i)
printf (" %3d", data [i]) ;
printf ("\n\n") ;
delay(10) ;
}
}

return 0 ;
}


dann alles wieder umgesteckt auf 3,3V Due...:
fluppt.

- - - Aktualisiert - - -

ps,

im Augenblick re-synced er sogar automatisch:
nach Rausnehmen einer i2c-Leitung stoppt die Transmission auf dem Slave

(blöderweise zählt der Raspi trotzdem weiter...: to do: error handling),

aber nach wiedereinstecken machen Raspi und Arduino wieder ganz normal weiter.

Peter(TOO)
10.02.2016, 09:33
Hallo,

klappt bei mir nicht mit Mega und Levelshifter:
für die ersten 10 bis 30 Arrays werden vom Slave Daten ausgetauscht, dann passiert am Mega plötzlich nichts mehr;
auch der Raspi kriegt keine neuen Daten mehr: i2c tot.

Für so etwas gibt es eigentlich nur eine Ursache: Störungen.

Entweder ist es ein Hardware-Problem, dann muss man am Error-Handlich arbeiten. Es sollte zumindest eine Störungsmeldung auftreten, welche eine Neu-Synchronisation ermöglicht. Wenn die Störung allerdings einen Latch-Up erzeugt, hilft nur Aus/Einschalten :-(

Oder es liegt an der Software. Typische Fehlerquellen sind Interrupts, weil sie ganz einfach das Timing "versauen", der Stack zu klein ist, ein Pointer in die Irre zeigt oder ein Register nicht gerettet/gestört wird.
Vor allem den Stack (Auto Variablen) muss man sich sehr genau ansehen. Zugriffe ausserhalb von Array-Grenzen führen zu sehr lustigen Effekten.

Bei einem meiner ersten Projekte(6502 @1MHz, Assembler) hatte ich im Schnitt 1x in der Wochen einen Programmabsturz. Manchmal, auch wiederholt, schon mach 1-2 Minuten. Die Ursache war dann, dass der Interrupt 1x pro Sekunde für einen Takt fälschlicherweise offen war, Wahrscheinlichkeit 1:1'000'000.

MfG Peter(TOO)

HaWe
10.02.2016, 10:00
wie gesagt: Tipps aus dem Blauen wieder ins Blaue bingen nichts.........:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

HaWe
10.02.2016, 17:52
update:
nicht nur mit dem Mega scheint es Probleme zu geben sondern auch mit anderen AVRs.
Uno habe ich keinen, aber ich habe jetzt einen Nano getestet:

Auch mit dem Nano (keine Pullups eingebaut, daher braucht er keine Levelshifter) dasselbe Phänomen wie beim Mega MIT Levelshiftern:

er überträgt eine Handvoll Zyklen lang (mal 2, mal 10, mal bis zu 30) und dann blockiert die Übertragung. Der Raspi erkennt dann auch hier den Arduino nicht mehr als Slave, Adresse 0x04 ist leer.

Nach resetten des Nanos geht es erst wieder kurz, dann wieder Schicht.

Jetzt bräuchte man wen, der ein Oszi hat (wenn man das überhaupt nachmessen kann). Es scheint vllt doch am Clock-Stretching zu liegen, was evtl besonders die AVRs betrifft, scheinbar weniger die ARMs.


hab jetzt die Datenausgabe auf dem Pi ein wenig geändert, um es besser verfolgen zu können:
Beim Lesen bleibt der Pi beim AVR (Nano und Mega) recht schnell hängen, beim Schreiben zählt er weiter - aber beim AVR kommt nichts mehr an.



// Raspberry Pi Master code to send/receive byte arrays
// to an Arduino as an I2C slave
//
// ver. 0.002a


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#include <errno.h>
#include <string.h>

#define MSGSIZE 30


unsigned char calcchecksum( unsigned char array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}



int main (void)
{

int fd, i ;
unsigned char test=0;
unsigned char data [MSGSIZE] ;

if ((fd = wiringPiI2CSetup (0x04) ) < 0)
{
fprintf (stderr, "Can't open RTC: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}


for (;;)
{
memset(data, 0, sizeof(data) );
data[0]= 0xff; // init for transmission error check
read (fd, data, MSGSIZE) ;
if( data[1] != calcchecksum( data ) ) {
// handle transmission error !
}
else {
printf (" read: ");
for (i = 0 ; i < 7 ; ++i)
printf (" %3d", data [i]) ;
//printf ("\n") ;
delay(10) ;

memset(data, 0, sizeof(data) );
data[5]= test++;
data[0]= 0xff;
data[MSGSIZE-1]= 0x04;
data[1] = calcchecksum( data );

write(fd, data, MSGSIZE) ;
printf (" write: ");
for (i = 0 ; i < 7; ++i)
printf (" %3d", data [i]) ;
printf ("\n\n") ;
delay(10) ;
}
}

return 0 ;
}




// Arduino code to send/receive byte arrays
// Arduino as an I2C slave
//
// ver. 0.002


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
#define MSGSIZE 30
byte recvarray[MSGSIZE]; // 0=0xff; 1=chksum; ...data...; MSGSIZE-1=SLAVE_ADDRESS
byte sendarray[MSGSIZE];

volatile int8_t flag=0;


//================================================== ===================================
//================================================== ===================================
void setup() {
int32_t i=0;

// Serial terminal window
i=115200;
Serial.begin(i);
Serial.print("Serial started, baud=");
Serial.println(i);

// Wire (i2c)
Wire.begin(SLAVE_ADDRESS); // start Arduino as a I2C slave, addr=0x04 (7-bit coded)

Wire.onReceive(receiveData ); // event when master array is sent
Wire.onRequest(sendData ); // event when master requests array to read

memset(sendarray, 0, sizeof(sendarray) ); // init send- and recv arrays
memset(recvarray, 0, sizeof(recvarray) );

Serial.print("I2C init: my slave address= ");
Serial.println(SLAVE_ADDRESS);
Serial.println("I2C init: done.");
Serial.println();

Serial.println("setup(): done.");

}


//================================================== ===================================


uint8_t calcchecksum(uint8_t array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}

//================================================== ===================================

void loop()
{
char sbuf[128];

Serial.println(); Serial.println();

// do something with the received data
// and then do something to build the sendarray [3]...[MSG_SIZE-2]

if (flag==1) {
//debug
sendarray[4] +=1;
}

sendarray[0] = 0xff; // 0 = start: 0xff == msg start flag
sendarray[2] = flag; // 2 = send back msg error flag
sendarray[MSGSIZE-1] = SLAVE_ADDRESS; // end of array: ID check

sendarray[1] = calcchecksum(sendarray); // 1 = calc new chksum
flag=0;

// debug output
sprintf(sbuf, "Sendarr[4]=%4d, [5]=%4d, Recvarr[4]=%4d, [5]=%4d",
sendarray[4], sendarray[5], recvarray[4], recvarray[5]) ;
Serial.println(sbuf);

delay(1); // short break for the cpu and the bus
}


//================================================== ===================================

void receiveData(int byteCount) {
int32_t i;
byte val;

while(Wire.available()<MSGSIZE) ; // wait for all bytes to complete
i=0; // init counter var
while(Wire.available()&& (i<MSGSIZE) ) // read all recv array bytes
{
val=Wire.read();
recvarray[i++]=val;
}

// check for transmission error
if( (recvarray[0] == 0xff)
&& (recvarray[1] == calcchecksum(recvarray))
&& (recvarray[MSGSIZE-1] == SLAVE_ADDRESS ) )
flag=1; // data ok
else
flag=127; // data faulty => handle rcv-error => flag =127
}

//================================================== ===================================

void sendData(){
// Wire.write writes data from a slave device in response to a request from a master
Wire.write(sendarray, MSGSIZE); // send own byte array back to master..
}



Nach kurzem Lauf wieder kein AVR-slave mehr dann an i2c detektiert

pi@raspberrypi ~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
erst nach Resetten ist 0x04 wieder da - beim nächsten Programmstart aber schnell wieder rausgekickt.

Wie gesagt, wie bisher aber kein Problem mit dem Due.

peterfido
10.02.2016, 17:53
Hallo,

die Pegelwandler (http://www.amazon.de/gp/product/B00M7U5DV2?psc=1&redirect=true&ref_=oh_aui_detailpage_o00_s00) sind da. Damit funktioniert der letzte Code. Da auch mein Raspi nach einiger Zeit den Slave nicht mehr finden konnte, habe ich doch noch ein USB-Kabel geopfert und die 5V-Ader durchtrennt, sodass der ARDUINO mit 3V3 läuft. Flashen und Seriell funktioniert alles. Bei der I2C-Verbindung nach einiger Zeit das gleiche Problem.

Solange die beiden miteinander 'reden' bleibt die Verbindung stabil. Beende ich das Master-Programm auf dem Raspi, erlischt nach einiger Zeit die LED auf dem ARDUINO und dann ist der Slave nicht mehr zu finden. Resete ich den ARDUINO, ohne das Masterprogramm am Raspi zu starten, erlischt oft, aber nicht immer, die LED auch wieder nach einiger Zeit und der Slave ist wech. Scheint, als ob der Slave-Code es nicht mag, wenn der Master nicht da ist.

Ich musste die BAUD-Rate auf dem ARDUINO auf 57600 runtersetzen. Bei 115200 BAUD kommt sowohl bei 3V3 als auch bei 5V nur Müll im Terminal an.

Beschäftigt man den ARDUINO zusätzlich noch etwas, gehen Daten verloren. Viel Luft ist also nicht. Wenn dieser als Gateway / 'Relaisstation' dienen soll, muss da ein gutes Protokoll her.


Das wars für Heute. Morgen Abend geht es weiter.

Gruß
Peterfido

HaWe
10.02.2016, 17:57
Danke für die Rückmeldung!
Bei mir erlischt ja schon die i2c-Verbindung ohne dass einer von beiden per Kabel abgetrennt wurde: die Daten-Verbindung hält höchstens 1 Sekunde!

Der Due dagegen bleibt ständig sicher verbunden und verkraftet sogar auch das zwischenzeitliche ab- und wieder anstöpseln und resynced sich automatisch.

Hast du auch einen normalen AVR (Uno oder Nano) ?

Peter(TOO)
10.02.2016, 20:30
Hallo Peterfido,

Ich musste die BAUD-Rate auf dem ARDUINO auf 57600 runtersetzen. Bei 115200 BAUD kommt sowohl bei 3V3 als auch bei 5V nur Müll im Terminal an.

Das sieht jetzt aber langsam nach Störungen aus!

z.B. eine schlechte Masseverbindung.
Oder der Oszillator ist instabil.

Lege mal eine zusätzlich Masseverbindung zwischen PC und den beiden kleinen, darf schon 1.5mm2 sein.

MfG Peter(TOO)

HaWe
10.02.2016, 21:29
Die Masseleitungen sind in beiden Fällen exakt gleich lang - es sind sogar dieselben Kabel, sie wurden nur umgesteckt. Die Masseleitungen der beiden Boards sind direkt miteinander verbunden, genau wie die i2c-Leitungen.
Und der Fehler tritt bei 2 verschiedenen AVRs auf, nicht aber bei einem ARM - mehrfach hin- und hergesteckt. Und er tritt auch auf, wenn die AVRs stand-allone laufen.
Auch andere User haben i.Ü, diesen AVR-spezifischen Fehler reproduziert - nicht nur in diesem Forum.

Im übrigen bitte ich dich, zuerst den Aufbau zu nachzubauen, das jetzige Verhalten zu überprüfen und dann deine Theorie zu testen. Teste es also erst selber und DANN poste!

Denn wie schon mehrfach gesagt: Tipps aus dem Blauen wieder ins Blaue bingen nichts.........:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

peterfido
11.02.2016, 16:04
Hallo,

so wie es aussieht, liegt es am MEGA, wenn die Kommunikation zusammenbricht. Mal hält dieser dann SCL auf Low und mal reagiert er einfach nicht mehr. Allerdings immer nach unterschiedlicher Zeit. Mal läuft es minutenlang durch und mal klemmt es nach wenigen Sekunden. Egal ob mit Pegelwandler oder direkt verbunden und 3V3 Versorgung des MEGA. Der MEGA hängt sich allerdings nicht weg. Die Hauptschleife läuft weiter.


Die Pegelwandler sind 1A. Selbst bei 24MHZ erkennt mein LA keine Verzögerung.

An einem Protokoll brauchen wir noch nicht zu arbeiten, solange die Verbindung unzuverlässig ist.

HaWe
11.02.2016, 16:32
hallo,
wie gesagt: mit dem NANO passiert genau dasselbe, in diesem Falle 5V ohne Pegelwandler.
Könnte ein Clock-Stretching Ding sein, das alle AVRs betrifft (nicht aber ARMs).

Hast du auch einen "normalen" Arduino (Uno, Nano, Micro) ?



ps,

guck mal hier:
https://www.raspberrypi.org/forums/viewtopic.php?p=870098#p769282 (https://www.raspberrypi.org/forums/viewtopic.php?p=870098#p769282)
https://www.raspberrypi.org/forums/viewtopic.php?p=870098#p870098

oberallgeier
11.02.2016, 17:22
Hi!
.. so wie es aussieht, liegt es am MEGA, wenn die Kommunikation zusammenbricht. Mal hält dieser dann SCL auf Low und mal reagiert er einfach nicht mehr ..Ich musste mal hier reinschaun. Über 30 Postings zu I²C - erinnerte mich an ein paar Probleme die ich vor Monaten mit diesem Bus/Protokoll hatte. Bei MIR war der Beginn der Lösung ein Oskarbildchen. Als ich die Flanken sah, überhaupt die Peaks . . . au weia. Busterminierung geändert - Bildchen - Taktrate geändert - Bildchen - aaahhhhh. Seit der Zeit habe ich soweit ich es in der aktuellen Testphase (Thema ist NICHT mehr I²C) sehe, bei Laufzeiten teils über eine Stunde (ok, das klingt nicht nach Wochen) keine Probleme. Übrigens hatte ich mal vor vielen Monaten in einem anderen Projekt erfolgreiche Versuche damit gemacht, dass ich das Clockstreching dynamisch begrenzt hatte.

peterfido
11.02.2016, 18:28
Hallo,

nein, ich habe nur den einen Arduino. Ein Oszi habe ich nicht. 'Nur' ein LA. Die Beispielcodes der Arduino IDE 'bleiben am Leben.' So dass ich darauf aufbauen nochmal was Neues erstelle. Allerdings nicht mehr heute.

Folgendes läuft schon einige Zeit durch:

MEGA:


// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

void setup() {
Wire.begin(4); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(57600); // start serial for output
}

void loop() {
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}


Raspi: (Bash-Script)



#!/bin/bash
#
#

d=0;
while [ true ];do
i2cset -y 1 0x04 3 $d
d=$(($d+1))
if [ $d -gt 255 ]; then
d=0
fi
sleep 0.005
done



Wobei gelegentlich 'write Failed' ausgegeben wird. Bei 10 ms Pausen war das nicht so.

HaWe
11.02.2016, 19:16
@oberallgeier:
dann probier es doch mal bitte aus: Raspi plus AVR-Arduino!
Du hast das Problem mit dem Clockstretching, das der Raspi nicht verträgt, doch verstanden, oder?
Verbinde beide Boards (3 Kabel), lade die Sourcecodes, guck was dein Vorschlag bringt!

Wie schon so oft gesagt:

Für alle Tipps bin ich natürlich offen, aber der, der sie vorschlägt, müsste schon in der Lage sein, die Verbindung ebenfalls herzustellen und bei sich selber vor Ort zu testen (d.h. er müsste auch einen Raspi und einen Arduino besitzen und sie entsprechend verbinden und seinen eigenen - bzw. unseren gemeinsamen, auf einander abgestimmten - Code testen können).

@peterfido:
bin sehr gespannt!

angeblich soll ja pigpio Clock-Stretching unterstützen, im Gegensatz zu wiringPi.... :-/

... nur wie und was muss man da machen? :confused:



ps,
Zambetti's i2c-Code war auch die Grundlage für meinen Arduino-Slave-Teil.
Grundfunktionen sind i.P. 100% identisch!
(Nur mein Code stellt sicher, dass keine inkompletten Arrays gesendet, empfangen oder verarbeitet werden, sondern erst, wenn alle Bytes komplett im i2c-Buffer drin sind ...und dann getestet sind auf Transmission Errors !)

HaWe
12.02.2016, 12:40
hierin könnte die Lösung des Clock-Stretching-Problems bei den AVRs verborgen liegen:
http://abyz.co.uk/rpi/pigpio/cif.html#bbI2CZip

(nur verstehen tu ich's leider nicht, geschweige denn das Coding dann... säääähr schwäääre Kost.... :-/

peterfido
12.02.2016, 18:02
Hallo,

ich habe mir zwischenzeitlich den SourceCode von i2cset und i2cget besorgt. Da wird SMBUS genutzt, um auf I2C zuzugreifen. Komme heute aber nicht zum proggen. Es gibt eine Begrenzung von 32 Byte pro Block. Da bist Du mit den 30 schon knapp dran.

Ich stelle mir ein Protokoll vor, wo entweder die Registeradresse mit übergeben wird oder diese auf 0 bleibt. Bei 0 soll der Arduino dann automatisch inkrementieren.

So braucht man auch nicht jedesmal die 30 (32) Bytes rüberschicken, wenn nur ein Byte geändert werden soll. Das spart Zeit, wenn der Arduino z.B. ein Display ansteuert. Darüber braucht man sich aber erst Gedanken zu machen, wenn die Kommunikation steht.

Wenn Du Dein verlinktes BitBang-Beispiel nutzen möchtest, dann kann jeder PIN genutzt werden. Die Pullups berücksichtigen.

Oben im Code

#include <pigpio.h>

und dann die Funktionen aufrufen. Klingt recht einfach. Damit fange ich morgen mal an.

HaWe
12.02.2016, 18:56
die Arrays hin- und her schicken hat sowohl remote-control als auch Portexpander- (Telemetrie-) Zwecke. Zum einen sollen vom Raspi aus Encodermotoren gesteuert werden, zum anderen sollen möglichst schnell (auch zum Update der Fernsteuerung) alle möglichen Sensoren auf dem Slave ausgelesen werden.
32 Bytes sind dazu mehr als knapp, besser wären mindestens 64, gerade weil Encoderwerte 32 bit lang sind.
Auch Werte von i2c- oder UART-Sensoren auf dem Arduino sollen an den Raspi übermittelt werden können, die oft floats sind (also ebenfalls 32 bit).
Der Fall, dass nur 1 Byte im Array geändert wird, wird also fast nie vorkommen.

Wenn es keine Möglichkeit gibt, den i2c buffer vom Raspi auf 64 Bytes zu erhöhen, müssen sich 2 Arduino-Boards die Arbeit teilen. Allerdings scheidet dann der Mega komplett aus, da er ja bereits jetzt am Bus über 3mA per Pegelwandler gegen die 5V Pullups ziehen muss, und 3mA ist die Höchstgrenze für SDA/SCL laut I2C-specs. Und weitere i2c-Geräte kommen ja sowieso noch hinzu (zum Glück aber nicht mehr als hundert) ;)

Ich komme daher immer mehr zu der Überzeugung, dass die AVRs zur Zeit eine Sackgasse sind, wegen clock-stretching, und speziell auch der Mega wegen seiner zusätzlichen Pullups.

Das bedeutet allerdings dann: nur DUEs werden zur Zeit Sinn machen, da nichts anderes funktioniert.

Oder, wie Gordon Henderson (Autor der wiringPi libs) schrieb, nur eins macht Sinn für die AVRs: "... a newer version of the kernel driver.. So one day..."

Trotzdem bin ich natürlich auf deine pigpio-Versuche gespannt, insbesondere mit mehreren Geräten am selben Bus.

peterfido
12.02.2016, 20:19
Da bleibt dann nur BitBang übrig. Da gibt es keine Einschränkungen, was die Puffergröße betrifft, da alles zu Fuss gemacht wird. DiePullups des Mega sollten sich mit etwas Geschick entfernen lassen. Wo hast Du die 3mA her? Die Pullups des Raspis scheinen 1k8 zu sein. Also knapp unter 2mA. Der MEGA hat bei 5V und 10k Pullups 0,5 mA. Den Strom des Pegelwandlers müsste dieser doch selbst verkraften. Nachgemessen habe ich es nicht.

Wenn der MEGA der einzige problematische Slave am Raspi ist, kann man auch ein eigenes Protokoll per BitBanging auf beiden Seiten verwenden. Bei Verwendung anderer PINs bleibt I2C für die anderen Slaves erhalten. Hätte den Vorteil, dass der MEGA nicht als Slave und Master arbeiten müsste. Oder halt im Multimaster-Betrieb. Oder SPI, da gibt es dann wieder Hardware-Puffer, welche von Vorteil sind, wenn der MEGA eh noch Einiges zu tun hat. Bei der Nutzung von Interrupts geht bei einer Zwei-Draht-Verbindung ohne Hardware-Puffer das ein oder andere Bit verloren.

Ich selbst brauche es nicht und sehe es nur als Herausforderung und kann es evtl. irgendwann doch mal brauchen. ;) Aktuell habe ich zwei Favoriten: Den SMBUS-Treiber und BitBang. Wobei BitBang auf dem ersten Blick wesentlich einfacher scheint.

HaWe
12.02.2016, 20:36
Die Info samt Berechnung stammt aus dem Arduino-Forum:

The Arduino Mega 2560 is the only board with those 10k resistors on the board for I2C. Any other board would be no problem.

Connect 5V with 10k to 3.3V with 1k8. That makes 3.55V
I don't like that, often 3.6V is the limit for 3.3V chips, and this is very close.

Using a dirty trick with a resistor to GND to lower it might also cause trouble. The Arduino Mega board needs 3.5V to see a I2C level as high.

With a level shifter, the Arduino has to pull both sides of the level shifter down. A level shifter has often 10k on both sides.
Total current:
5V with 10k and 10k : 1mA
3.3V with 1k8 and 10k : 2.16mA
Together it is above 3mA, which is specified as the maximum current by the official I2C standard. But that 3mA is not very strict, it will work

Bitbang ist ja, was im Prinzip auch pigpio macht bzw. machen kann.

SPI ist keine Option, weil SPI bereits auf dem Arduino voll ausgeschöpft ist (84MBit/s DMA für TFT).
Außerdem ist i2c Pflicht, weil ja zusätzlich MCPs und PCFs und auch der CMPS11 gemeinsam dran sollen.

SMBus ist aber nichts anderes als eine Raspi-I2C-Implementierung, oder irre ich mich?


ps,
leider ist joan nicht sehr hilfsbereit für die Implementierung ihrer pigpio API-libs. Es werden zwar Links zur Verfügung gestellt (s.o.), aber wie es jetzt genau funktioniert anstelle von read() und write().... Schweigen im Walde.

Selbst Gordon Henderson war es bisher nicht klar, dass pigpio überhaupt clock-stretching per bitbang zur Verfügung stellen könnte.

Peter(TOO)
13.02.2016, 01:16
Hallo,

SMBus ist aber nichts anderes als eine Raspi-I2C-Implementierung, oder irre ich mich?

I2C wurde von Phlips Anfang der 80er entwickelt um Chips in Fernsehern einfach zu verbinden.

SMBus basiert auf dem I2C und wurde 1995 von Intel veröffentlicht ud war für PCs gedacht um Jumper zu ersetzen, Seriennummern und Parameter zu setzen und abzufragen. z.B. haben die Speichermodule ein Rom, in welchem Grösse, Timing-Parameter usw. abgelegt sind.

SMBus funktioniert zwischen 10kHz und 100kHz, i2C DC bis 400kHz und 2MHz.
SMBus kennt ein Timeout (35ms).
Die Pegel sind etwas unterschiedlich

MfG Peter(TOO)

peterfido
13.02.2016, 08:29
Hallo,

die BitBang-Methode läuft bei mir überhaupt nicht. Es ist auch kein Beispiel vorhanden. Selbst, wenn ich als SDA und SCL alle GPIOs durchteste, zeigt mein LA keine Regung.

Die RawSend Methode läuft bis 32 Bytes am Stück. Gibt man mehr an, wird automatisch auf 32 Bytes reduziert.
Das lässt sich auch für mehr Bytes nutzen, indem man z.B. immer 31 Bytes verschickt, wo im ersten die Blocknummer angegeben ist und dann 30 Nutzbytes hinterher. Weiter kann man das erste Byte auch dazu nutzen, Kommandos zu versenden. Z.B. 'Sende mir Block x zurück', 'Starte Neu', 'Wiederhole dein Anliegen', usw.

Der Vorteil der pigpio ist, dass man mehrere Handles öffnen kann und so 'bequem' die einzelnen Slaves ansprechen kann.

Hin und wieder kam bei meinen Tests der nichtssagende Fehler -82. Dann hilft nur, den MEGA neu zu Starten.
Die BeispielCodes werden vom gcc angemeckert (inkompatible Pointer Typen). Das ist dann zu korrigieren.

Bei Deinem Projekt befürchte ich bald ein Timingproblem. Wenn der Raspi ständig Daten sendet und haben möchte, bleibt kaum Zeit für die anderen Dinge. Bei meinen Tests langweilt sich der MEGA.

Edit:
Bei Fehler -82 muss meist der MEGA zurückgesetzt werden.

peterfido
13.02.2016, 11:11
Hallo,

ich sehe da ein Problem im ARDUINO-Code.

Der hängt sich weg, auch wenn man zwischen Senden und Empfangen eine Sekunde Pause einlegt.
Demnach läuft kein Puffer über, aber irgendetwas ist.

Meine aktuellen Codes:
MEGA:


// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

#define REGSIZE 240

byte rspeicher[REGSIZE];
byte wspeicher[REGSIZE];
byte puffer[32];
byte Register=1;
byte rdblock=0;
byte wrblock=0;
byte pos=0;
byte fertig=0;

void setup() {
Wire.begin(4); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
// Wire.onReceive(receiveEventRoh); // register event
Wire.onRequest(requestEvent); // register event
Serial.begin(57600); // start serial for output
/* for(byte i=0;i<REGSIZE;i++){
wspeicher[i]=i;

}*/
Serial.println();
Serial.println("Starte I2C-Test");
}

void loop() {
byte i=0;
delay(100);
if (fertig !=0){
fertig=0;
for (i=0;i<REGSIZE;i++){
wspeicher[i]=rspeicher[i];
Serial.print(rspeicher[i]);
Serial.print (" ");
}
Serial.println();
}
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
rdblock = Wire.read();
if (rdblock<=7){
pos=0;
while (0 < Wire.available()) {
if (pos<30){
rspeicher[rdblock*30+pos] = Wire.read();
pos++;
}
}
if (rdblock==7){
fertig=1;
}
}else{
if (rdblock >=10 && rdblock <=17){
wrblock=rdblock-10;
Serial.print("Leseblock: ");
Serial.println(wrblock);
}
}
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEventRoh(int howMany) {
while (0 < Wire.available()) {
byte x=Wire.read();
Serial.print (x);
Serial.print (" ");
}
Serial.println();
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
//Wire.write(speicher[Register],1);
memcpy( &puffer[1],&wspeicher[wrblock * 30],30);
puffer[0]=wrblock;
Wire.write(puffer,31);
}

Raspberry Pi:


// gcc -Wall -pthread -o /var/scripte/i2cmaster01 /var/scripte/i2cmaster01.c -lpigpio -lrt
// /var/scripte/i2cmaster01
//I2C mit pipgio
//peterfido
//V0.0.1
#include <stdio.h>
#include <stdlib.h>
//#include <stdarg.h>
#include <string.h>
//#include <ctype.h>
#include <unistd.h>

#include <signal.h>
#include <pigpio.h>


//#define SDA 3
//#define SCL 5
#define BAUD 100
#define ADDRESS 0x04
#define MSGSIZE 240
#define LOOPS 30
char empfdata[MSGSIZE]; //
char senddata[MSGSIZE];
char commando[32];

int handle=0;
int handles=-1;
unsigned int laenge=0;

void handleSigInt( int parameter );


void handleSigInt( int parameter )
{
int res=0;
int dl=0;
if (handles >= 0){
for (dl=0;dl<handles;dl++){
res=i2cClose(dl);
printf("%d geschlossen: %d\n",dl, res);
}
}
gpioTerminate();
printf( "\nSIGINT wurde augeloest - Programm wird beendet\n" );

exit( 1 );
}

void senden() {

int res=0;
int i=0;
char wrblock=0;

for (wrblock=0;wrblock<=7;wrblock++){
handle=i2cOpen(1,ADDRESS,0);
handles ++;
if (handle>=0){
laenge=31;
printf("Oeffnen OK %d\n",handle);
res=0;
memcpy( &commando[1],&senddata[wrblock * 30],laenge);
commando[0]=wrblock;
res=res+i2cWriteDevice(handle,commando,laenge);
usleep(5000);

for(i=0;i<laenge;i++){
printf("%d ",commando[i]);
}
printf("\n");

if (res==0){
printf("Senden OK\n");

}else{
printf("I2C-Fehler: %d\n", res);
}
res=i2cClose(handle);

if (res!=0){
printf("Fehler beim schliessen: %d\n", res);
}else{
handles--;
}
}else{
printf("Fehler beim oeffnen: %d\n", res);
}
}
}

void empfangen() {

int res=0;
int i=0;
char rdblock=0;
for (rdblock=0;rdblock<=7;rdblock++){
handle=i2cOpen(1,ADDRESS,0);
handles ++;
if (handle>=0){
laenge=31;
printf("Oeffnen OK %d\n",handle);
commando[0]=rdblock+10;
res=i2cWriteDevice(handle,commando,1);
if (res==0){

usleep(30000);
res=i2cReadDevice(handle,commando,laenge);
if (res>0){
/* printf("Empfangen:\n");
for(i=0;i<laenge;i++){
printf("%d ",commando[i]);
}
printf("\n");*/
// memcpy( &commando[1],&empfdata[commando[0] * 30],laenge-1);
for (i=0;i<laenge-1;i++){
empfdata[commando[0]*30+i]=commando[i+1];
}
}else{
printf("Fehler beim Blockeinlesen: %d\n", res);
}
}else{
printf("Fehler beim Leseblock schreiben %d\n", rdblock);
}
res=i2cClose(handle);//+i2cClose(handle1);

if (res!=0){
printf("Fehler beim schliessen: %d\n", res);
}else{
handles--;
}

}else{
printf("Fehler beim oeffnen: %d\n", res);
}
}
printf("Empfangen:\n");
for(i=0;i<MSGSIZE;i++){
printf("%d ",empfdata[i]);
}
}

int vergleichen()
{
unsigned int i=0;
int ret=0;
for (i=0;i<MSGSIZE;i++){
if (empfdata[i]!=senddata[i]){
ret=-1;
break;
}
}
return ret;
}

int main(int argc, char **argv)
{
int i=0;
int dg=0;

/* for(i=0;i<MSGSIZE;i++){
senddata[i]=i;
}*/
signal( SIGINT, &handleSigInt );
signal( SIGTERM, &handleSigInt );
if (gpioInitialise() < 0)
{
printf("Fehler beim Initialisieren von gpio!");
gpioTerminate();
}else{
for(dg=0;dg<LOOPS;dg++)
{
srand(time(NULL));
for(i=0;i<MSGSIZE;i++){
senddata[i]=rand() % 255;
}
senden();
// usleep(100000);
sleep(1);
empfangen();
// usleep(100000);
sleep(1);
if (vergleichen()==0){
printf("Daten OK\n");
}else{
printf("Daten fehlerhaft\n");
}
}
}

gpioTerminate();

return 0;
}

HaWe
13.02.2016, 11:45
wenn ich in meinen eigenen Code (siehe https://www.roboternetz.de/community/threads/68692-Raspi-C-C-Raspi-als-I2C-Master-byte-arrays-zu-Arduino-slave-hin-her-schicken?p=623669&viewfull=1#post623669) in der Loop statt delay(1) ein delay(2000) eingebe, habe ich kein Problem mit der Verbindung per Arduino DUE -

der Raspi sendet zwar lustig vor sich hin, aber der Arduino sendet und empfängt immer im 2-Sekundentakt die dann jeweils aktuellsten Daten:

Sendarr[4]= 36, [5]= 0, Recvarr[4]= 0, [5]= 93


Sendarr[4]= 37, [5]= 0, Recvarr[4]= 0, [5]= 168


Sendarr[4]= 38, [5]= 0, Recvarr[4]= 0, [5]= 243


Sendarr[4]= 39, [5]= 0, Recvarr[4]= 0, [5]= 61


Sendarr[4]= 40, [5]= 0, Recvarr[4]= 0, [5]= 133


Sendarr[4]= 41, [5]= 0, Recvarr[4]= 0, [5]= 209


Sendarr[4]= 42, [5]= 0, Recvarr[4]= 0, [5]= 29


Sendarr[4]= 43, [5]= 0, Recvarr[4]= 0, [5]= 104


Sendarr[4]= 44, [5]= 0, Recvarr[4]= 0, [5]= 179


Sendarr[4]= 45, [5]= 0, Recvarr[4]= 0, [5]= 255


Sendarr[4]= 46, [5]= 0, Recvarr[4]= 0, [5]= 75


Sendarr[4]= 47, [5]= 0, Recvarr[4]= 0, [5]= 151

- - - Aktualisiert - - -

ps,
auch bei mir funktioniert dann
#define MSGSIZE 32
einwandfrei.

peterfido
13.02.2016, 21:35
Hallo,

auch möglich, dass der Raspi durch sein Multitasking I2C etwas aus dem Takt bringt und der Code für den MEGA das nicht mag.

Aktuell habe ich es soweit, dass beide Seiten Fehler erkennen und danach dann 'einfach' weitermachen. Läuft schon eine Weile durch.

Beschäftige ich den MEGA mit en paar UART-Ausgaben, dann steigt die Fehlerquote an. Somit ist da nicht wirklich viel Luft für Dein Vorhaben. Da der Raspi mit vielen Sensoren und Slaves umgehen kann, würde ich dem die meiste Arbeit aufbürden und den MEGA nur für 'kritische' Aufgaben nutzen, da meiner Erfahrung nach die AVRs zuverlässiger arbeiten. Im Zweifel den Watchdog aktivieren.

Raspi:



// gcc -Wall -pthread -o /var/scripte/i2cmaster01 /var/scripte/i2cmaster01.c -lpigpio -lrt
// /var/scripte/i2cmaster01
//I2C mit pipgio
//peterfido
//V0.0.2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <signal.h>
#include <pigpio.h>

#define ADDRESS 0x04
#define MSGSIZE 240
char empfdata[MSGSIZE]; //
char senddata[MSGSIZE];
char commando[32];

int handle=0;
int handles=-1;
unsigned int laenge=0;

void handleSigInt( int parameter );


void handleSigInt( int parameter )
{
int res=0;
int dl=0;
if (handles >= 0){
for (dl=0;dl<handles;dl++){
res=i2cClose(dl);
printf("%d geschlossen: %d\n",dl, res);
}
}
gpioTerminate();
printf( "\nSIGINT wurde augeloest - Programm wird beendet\n" );

exit( 1 );
}

void schreiben() {

int res=0;
int i=0;
char wrblock=0;
int Fehler=0;

for (wrblock=0;wrblock<=7;wrblock++){

laenge=31;
memcpy( &commando[1],&senddata[wrblock * 30],laenge);
commando[0]=wrblock;
res=i2cWriteDevice(handle,commando,laenge);
if (res!=0){
printf("S I2C-Fehler: %d, Block: %d\n", res,wrblock);
Fehler++;
wrblock--;
usleep(15000);
if (Fehler==10){
break;
}
}
usleep(15000);
}
printf("Gesendet:\n");
for(i=0;i<MSGSIZE;i++){
printf("%d ",senddata[i]);
}
printf("\n");
}

void lesen() {

int res=0;
int i=0;
char rdblock=0;
int Fehler=0;

for (rdblock=0;rdblock<=7;rdblock++){

laenge=31;
commando[0]=rdblock+10;
res=i2cWriteDevice(handle,commando,1);
if (res==0){
usleep(30000);
res=i2cReadDevice(handle,commando,laenge);
if (res==laenge){
printf("Empfangene Daten: %d, Block: %d\n",res,rdblock);

for (i=0;i<laenge-1;i++){
empfdata[commando[0]*30+i]=commando[i+1];
}
}else{
printf("E Fehler beim Blockeinlesen: %d, Block: %d\n", res,rdblock);
Fehler++;
rdblock--;
usleep(15000);
if (Fehler==10){
break;
}
}
}else{
printf("E Fehler beim Leseblock schreiben %d, Block: %d\n", res,rdblock);
break;
}
}
printf("Empfangen:\n");
for(i=0;i<MSGSIZE;i++){
printf("%d ",empfdata[i]);
}
printf("\n");
}

int vergleichen()
{
unsigned int i=0;
int ret=0;
for (i=0;i<MSGSIZE;i++){
if (empfdata[i]!=senddata[i]){
ret=-1;
break;
}
}
return ret;
}

int main(int argc, char **argv)
{
int res=0;
int i=0;
int dg=1;
unsigned int Fehler=0;

signal( SIGINT, &handleSigInt );
signal( SIGTERM, &handleSigInt );
if (gpioInitialise() < 0)
{
printf("Fehler beim Initialisieren von gpio!");
gpioTerminate();
}else{
handle=i2cOpen(1,ADDRESS,0);
if(handle>=0){
handles ++;
printf("\n\n\nStarte I2C-Test (%d)\n\n",handle);
while (1)
{
srand(time(NULL));
for(i=0;i<MSGSIZE;i++){
senddata[i]=rand() % 255;
}
schreiben();
usleep(100000);
lesen();
usleep(100000);
if (vergleichen()==0){
printf("Daten OK %d\n",dg);
Fehler=0;
}else{
printf("***************************** Daten fehlerhaft %d *****************************\n",dg);
Fehler++;
usleep(500000);
if (Fehler==10){
break;
}
}
}
}else{
printf("E Fehler beim Oeffnen: %d\n", handle);
}
}
res=i2cClose(handle);

if (res!=0){
printf("E Fehler beim Schliessen: %d\n", res);
}else{
handles--;
printf("E Schliessen OK %d\n",handle);
}

gpioTerminate();

return 0;
}


MEGA:


// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

#define REGSIZE 240

byte rspeicher[REGSIZE];
byte wspeicher[REGSIZE];
byte puffer[32];
byte Register=1;
byte rdblock=0;
byte wrblock=0;
byte pos=0;
byte fertig=0;
long dg=0;
long timeout=0;

void setup() {
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
// Wire.onReceive(receiveEventRoh); // register event
Wire.onRequest(requestEvent); // register event
Serial.begin(57600); // start serial for output
/* for(byte i=0;i<REGSIZE;i++){
wspeicher[i]=i;

}*/
Serial.println();
Serial.println("Starte I2C-Test");
}

void loop() {
byte i=0;
delay(100);
timeout++;
if (timeout==30){
timeout=0;
Wire.begin(4);
Serial.println("Fehler!");
dg=0;
}

if (fertig !=0){
fertig=0;
timeout=0;
dg++;
Serial.println(dg);

for (i=0;i<REGSIZE;i++){
wspeicher[i]=rspeicher[i];
// Serial.print(rspeicher[i]);
// Serial.print (" ");
}
// Serial.println();
}
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
byte x=0;
if(howMany == 31){
rdblock = Wire.read();
if (rdblock<=7){
pos=0;
while (0 < Wire.available()) {
if (pos<30){
rspeicher[rdblock*30+pos] = Wire.read();
pos++;
}
}
if (rdblock==7){
fertig=1;
}
}
}
if (howMany==1){
x=Wire.read();
if (x >=10 && x <=17){
wrblock=x-10;
// Serial.print("Leseblock: ");
// Serial.println(wrblock);
}
}
while (0 < Wire.available()) {
x=Wire.read();
}
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEventRoh(int howMany) {
while (0 < Wire.available()) {
byte x=Wire.read();
// Serial.print (x);
// Serial.print (" ");
}
// Serial.println();
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
//Wire.write(speicher[Register],1);
memcpy( &puffer[1],&wspeicher[wrblock * 30],30);
puffer[0]=wrblock;
Wire.write(puffer,31);
}

HaWe
14.02.2016, 08:25
hallo,
ich verstehe jetzt deinen Code nicht mehr -
ist es noch so wie in meinem Ausgangs-Code,

- dass der Raspi im 10ms-Takt (künftig schneller) zum Arduino 32 Bytes schickt und dann, wenn sie angekommen sid, 32 neue Bytes von ihm zurück liest
- und dass der Arduino so schnell wie möglich (also mindestens im 1ms- Takt) seinen Sende-Array zum Auslesen aktualisiert und bereitstellt?

Der Arduino muss dies automatisch tun, so schnell wie möglich, es darf keine Anforderung vom Raspi nötig sein außer ein onRequest und/oder ein onReceive(), um sie zu empfangen oder weg zu "senden".

Später in der "richtigen" Anwendung wird der Arduino seine digitalen und anlalogen Pins per Timer Interrupt (AVR) oder Task (DUE) (100µs) ständig (quasi im Hintergund bzw. per Parallel-Task) aktualisieren, damit sie beim Abruf immer in der am weitest aktualisiertesten Version zur Verfügung stehen. Kommt dann ein onRequest, kann abgerufen werden, was bis dahin bekannt ist.
Genauso muss jederzeit alles angenommen werden können, was vom Master gesendet wurde, per onReceive Event. Eine gesonderte Funktion (ebenfalls per Timer-Interrupt oder Task) verarbeitet sie dann weiter.

Der Arduino-Code soll dazu möglichst unverändert bleiben (außer clock-stretching vermeiden)
und der Raspi-Code ebenfalls, außer dass er clock-stretching besser verträgt, d.h. die normalen read() und write() Befehle für I2C müssten durch andere, clock-tolerantere, erstetzt werden.

Raspi:


// Raspberry Pi Master code to send/receive byte arrays
// to an Arduino as an I2C slave
//
// ver. 0.002b


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#include <errno.h>
#include <string.h>

#define MSGSIZE 32


#define ARDU1_SLV_ADDR 0x04


uint8_t calcchecksum( uint8_t array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}



int main (void)
{

int fd, i ;
uint8_t test=0;
uint8_t data [MSGSIZE] ;

if ((fd = wiringPiI2CSetup ( ARDU1_SLV_ADDR) ) < 0)
{
fprintf (stderr, "Can't open RTC: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}


for (;;)
{
memset(data, 0, sizeof(data) );
data[0]= 0xff; // init for transmission error check
read (fd, data, MSGSIZE) ;
if( data[1] != calcchecksum( data ) ) {
// handle transmission error !
}
else {
printf (" read: ");
for (i = 0 ; i < 7 ; ++i)
printf (" %3d", data [i]) ;
//printf ("\n") ;
delay(10) ;

memset(data, 0, sizeof(data) );
data[5]= test++;
data[0]= 0xff;
data[MSGSIZE-1]= ARDU1_SLV_ADDR ;
data[1] = calcchecksum( data );

write(fd, data, MSGSIZE) ;
printf (" write: ");
for (i = 0 ; i < 7; ++i)
printf (" %3d", data [i]) ;
printf ("\n\n") ;
delay(10) ;
}
}

return 0 ;
}



Arduino:


// Arduino code to send/receive byte arrays
// Arduino as an I2C slave
//
// ver. 0.002b


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
#define MSGSIZE 32
byte recvarray[MSGSIZE]; // 0=0xff; 1=chksum; ...data...; MSGSIZE-1=SLAVE_ADDRESS
byte sendarray[MSGSIZE];

volatile int8_t flag=0;


//================================================== ===================================
//================================================== ===================================
void setup() {
int32_t i=0;

// Serial terminal window
i=115200;
Serial.begin(i);
Serial.print("Serial started, baud=");
Serial.println(i);

// Wire (i2c)
Wire.begin(SLAVE_ADDRESS); // start Arduino as a I2C slave, addr=0x04 (7-bit coded)

Wire.onReceive(receiveData ); // event when master array is sent
Wire.onRequest(sendData ); // event when master requests array to read

memset(sendarray, 0, sizeof(sendarray) ); // init send- and recv arrays
memset(recvarray, 0, sizeof(recvarray) );

Serial.print("I2C init: my slave address= ");
Serial.println(SLAVE_ADDRESS);
Serial.println("I2C init: done.");
Serial.println();

Serial.println("setup(): done.");

}


//================================================== ===================================


uint8_t calcchecksum(uint8_t array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}

//================================================== ===================================

void loop()
{
char sbuf[128];

Serial.println(); Serial.println();

// do something with the received data
// and then do something to build the sendarray [3]...[MSG_SIZE-2]

if (flag==1) {
//debug
sendarray[4] +=1;
}

sendarray[0] = 0xff; // 0 = start: 0xff == msg start flag
sendarray[2] = flag; // 2 = send back msg error flag
sendarray[MSGSIZE-1] = SLAVE_ADDRESS; // end of array: ID check

sendarray[1] = calcchecksum(sendarray); // 1 = calc new chksum
flag=0;

// debug output
sprintf(sbuf, "Sendarr[4]=%4d, [5]=%4d, Recvarr[4]=%4d, [5]=%4d",
sendarray[4], sendarray[5], recvarray[4], recvarray[5]) ;
Serial.println(sbuf);

delay(1); // short break for the cpu and the bus
}


//================================================== ===================================

void receiveData(int byteCount) {
int32_t i;
byte val;

while(Wire.available()<MSGSIZE) ; // wait for all bytes to complete
i=0; // init counter var
while(Wire.available()&& (i<MSGSIZE) ) // read all recv array bytes
{
val=Wire.read();
recvarray[i++]=val;
}

// check for transmission error
if( (recvarray[0] == 0xff)
&& (recvarray[1] == calcchecksum(recvarray))
&& (recvarray[MSGSIZE-1] == SLAVE_ADDRESS ) )
flag=1; // data ok
else
flag=127; // data faulty => handle rcv-error => flag =127
}

//================================================== ===================================

void sendData(){
// Wire.write writes data from a slave device in response to a request from a master
Wire.write(sendarray, MSGSIZE); // send own byte array back to master..

peterfido
14.02.2016, 10:39
Hallo,

ich habe nun die Funktion verstanden und den BitBAng Modus zum laufen zu bekommen.

Die Ergebnisse sind ernüchternd. Daten zum AVR bekomme ich hin. Beim Lesen hakt es noch arg. 1 Byte kein Problem. Bei mehreren steht dann der Bus.

Der Resync nach einem Fehler klappt nun nicht mehr.

HaWe
14.02.2016, 11:42
hi,
Mist.
Ich denke fast, wir sollten es aufgeben, zuviel Aufwand. Vllt gibt ja irgendwann nen neuen Jessie-Kernel, der clock-stretching unterstützt, wie Gordon Henderson schrieb... irgendwann halt...
Solange muss ich dann mit meinen DUEs vorlieb nehmen.

- - - Aktualisiert - - -

angeblich gibt es sogar schon etwas Bewegung in dieser Sache:

https://github.com/raspberrypi/linux/pull/1241

peterfido
14.02.2016, 14:59
Hallo,

es sieht nicht so gut aus. Anbei meine aktuellen Testcodes, wo 240 Bytes hin und zurück geschickt und verglichen werden.

MEGA:


// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

#define REGSIZE 240

byte rspeicher[REGSIZE];
byte wspeicher[REGSIZE];
byte puffer[32];
byte Register=1;
byte rdblock=0;
byte wrblock=0;
byte pos=0;
byte fertig=0;
long dg=0;
long timeout=0;

void setup() {
Wire.begin(4); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event
Serial.begin(57600); // start serial for output

Serial.println();
Serial.println("Starte I2C-Test");
}

void loop() {
byte i=0;
delay(100);
timeout++;
if (timeout==90){
timeout=0;
Wire.begin(4);
Serial.println("TimeOut!");
dg=0;
}

if (fertig !=0){
fertig=0;
timeout=0;
dg++;
Serial.println(dg);

for (i=0;i<REGSIZE;i++){
wspeicher[i]=rspeicher[i];
/* Serial.print(rspeicher[i]);
Serial.print (" ");*/
}
// Serial.println();
}
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
byte x=0;

if(howMany == 2){
rdblock = Wire.read();
if (rdblock<=240){
rspeicher[rdblock]=Wire.read();
}
if (rdblock==REGSIZE-1){
fertig=1;
}
}else{
if (howMany == 1){
x=Wire.read();
if (x >=10 && x <=250){
wrblock=x-10;
/* Serial.print("Lesebyte: ");
Serial.println(wrblock);*/
}
}else{
Serial.print ("Anzahl Daten: ");
Serial.println(howMany);
while (0 < Wire.available()) { //überflüssiges lesen
x=Wire.read();
}
}
}
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
//Wire.write(speicher[Register],1);
puffer[0]=wrblock;
puffer[1]=wspeicher[puffer[0]];
Wire.write(puffer,2);
/* Serial.print("Sendebyte: ");
Serial.println(puffer[0]);
/* Serial.print(", Wert: ");
Serial.println(puffer[1]);*/

}


Raspi HW:


// gcc -Wall -pthread -o /var/scripte/i2cmaster01 /var/scripte/i2cmaster01.c -lpigpio -lrt
// /var/scripte/i2cmaster01
//I2C mit pipgio
//peterfido
//V0.0.2
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pigpio.h>

#define ADDRESS 0x04
#define MSGSIZE 240
char empfdata[MSGSIZE]; //
char senddata[MSGSIZE];
char commando[32];

int handle=0;
int handles=-1;
unsigned int laenge=0;

volatile sig_atomic_t done = 0;

void term(int signum)
{
done = 1;
/*
int res=0;
int dl=0;
if (handles >= 0){
for (dl=0;dl<handles;dl++){
res=i2cClose(dl);
printf("%d geschlossen: %d\n",dl, res);
}
}
gpioTerminate();
printf( "\nSIGINT wurde augeloest - Programm wird beendet\n" );

exit( 1 );*/
}

void schreiben() {

int res=0;
// int i=0;
int wrblock=0;
int Fehler=0;

for (wrblock=0;wrblock<MSGSIZE;wrblock++){

commando[0]=wrblock;
commando[1]=senddata[wrblock];
res=i2cWriteDevice(handle,commando,2);
if (res!=0){
printf("S I2C-Fehler: %d, Block: %d\n", res,wrblock);
Fehler++;
/* wrblock--;
usleep(15000);
if (Fehler==10){
break;
}*/
break;
}
usleep(15000);
}

/* printf("Gesendet:\n");
for(i=0;i<MSGSIZE;i++){
printf("%d ",senddata[i]);
}
printf("\n");
*/
}

void lesen() {

int res=0;
// int i=0;
int rdblock=0;
int Fehler=0;

for (rdblock=0;rdblock<MSGSIZE;rdblock++){

commando[0]=rdblock+10;
res=i2cWriteDevice(handle,commando,1);
if (res==0){
usleep(1000);
res=i2cReadDevice(handle,commando,2);
if (res==2){
// printf("Empfangene Daten: %d, Block: %d\n",res,rdblock);
if (rdblock==commando[0]){
empfdata[rdblock]=commando[1];
}
}else{
printf("E Fehler beim Blockeinlesen: %d, Block: %d\n", res,rdblock);
Fehler++;
rdblock--;
usleep(15000);
if (Fehler==10){
break;
}
break;
}
}else{
printf("E Fehler beim Leseblock schreiben %d, Block: %d\n", res,rdblock);
break;
}
}
/*
printf("Empfangen:\n");
for(i=0;i<MSGSIZE;i++){
printf("%d ",empfdata[i]);
}
printf("\n");
*/
}

int vergleichen()
{
unsigned int i=0;
int ret=0;
for (i=0;i<MSGSIZE;i++){
if (empfdata[i]!=senddata[i]){
ret=-1;
break;
}
}
return ret;
}

int main(int argc, char **argv)
{
int res=0;
int i=0;
long dg=1;
long maxdg=0;
unsigned int Fehler=0;

struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);

if (gpioInitialise() < 0)
{
printf("Fehler beim Initialisieren von gpio!");
gpioTerminate();
}else{
handle=i2cOpen(1,ADDRESS,0);
if(handle>=0){
handles ++;
printf("\n\n\nStarte I2C-Test (%d)\n\n",handle);
while (!done)
{
srand(time(NULL));
for(i=0;i<MSGSIZE;i++){
senddata[i]=rand() % 255;
}
schreiben();
usleep(100000);
lesen();
usleep(100000);
if (vergleichen()==0){
printf("Daten OK %ld (%ld)\n",dg,maxdg);
Fehler=0;
dg++;
}else{
printf("***************************** Daten fehlerhaft %ld *****************************\n",dg);
Fehler++;
dg=0;
if (dg>maxdg){
maxdg=dg;
}
sleep(1);
if (Fehler==100){
break;
}
}
}
}else{
printf("E Fehler beim Oeffnen: %d\n", handle);
}
}
res=i2cClose(handle);

if (res!=0){
printf("E Fehler beim Schliessen: %d\n", res);
}else{
handles--;
printf("E Schliessen OK %d\n",handle);
}

gpioTerminate();

return 0;
}




Raspi BitBang:


// gcc -Wall -pthread -o /var/scripte/bbi2cmaster /var/scripte/bbi2cmaster.c -lpigpio -lrt
// /var/scripte/bbi2cmaster
//I2C mit pipgio
//peterfido
//V0.0.2
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pigpio.h>

#define SDA 2
#define SCL 3
#define TAKT 100000
#define PAUSEN 5000
#define ADDRESS 0x04
#define MSGSIZE 240



char empfdata[MSGSIZE]; //
char senddata[MSGSIZE];
char commando[64];
char puffer[12];

unsigned int laenge=0;

volatile sig_atomic_t done = 0;

void term(int signum)
{
done = 1;
}

int I2CResetBus(void)
{
char i;
int res=0;
if(gpioRead(SDA) && gpioRead(SCL)) {
return 0;
}
gpioSetMode(SCL, PI_INPUT);
gpioSetMode(SDA, PI_INPUT);
gpioSetPullUpDown(SDA, PI_PUD_UP); // Sets SDA pull-up.
gpioSetPullUpDown(SCL, PI_PUD_UP); // Sets SDA pull-up.
usleep(50);
if(!gpioRead(SCL)) {
return -1; /* SCL wird extern auf Low gehalten, nix zu machen */
}
for(i = 0; i<9; i++) {
gpioSetMode(SCL, PI_OUTPUT);
gpioWrite(SCL, 0);
usleep(50);
gpioSetMode(SCL, PI_INPUT);
gpioSetPullUpDown(SCL, PI_PUD_UP); // Sets SDA pull-up.
usleep(50);
if(gpioRead(SDA)) {
break; /* SDA ist high STOP */
}
} /* for */
if(!gpioRead(SDA)) {
return -1;
}
commando[0]= 3; //stop
commando[1]= 0; // Fertig
res=bbI2CZip(SDA,commando,2,NULL,0);
if (res!=0){
printf("Fehler beim Reset!\n");
}
if(gpioRead(SDA) && gpioRead(SCL)){
return 0;
}else{
return -1;
}
}


void schreiben() {

int res=0;
// int i=0;
int wrblock=0;
int Fehler=0;

for (wrblock=0;wrblock<MSGSIZE;wrblock++){

commando[0]= 4; //'Adresse setzen ankündigen
commando[1]= ADDRESS; //'Adresse übergeben
commando[2]= 2; //start
commando[3]= 7; //'Bytes senden
commando[4]= 2; //'Anzahl
commando[5]= wrblock; //Block
commando[6]= senddata[wrblock]; //Wert
commando[7]= 3; //stop
commando[8]= 0; //keine weiteren Parameter
res=I2CResetBus();
res=bbI2CZip(SDA,commando,9,NULL,0);
res=I2CResetBus();
if (res!=0){
printf("S I2C-Fehler: %d, Block: %d\n", res,wrblock);
Fehler++;
wrblock--;
usleep(PAUSEN*3);
if (Fehler==10){
break;
}
}
usleep(PAUSEN);
}
/*
printf("Gesendet:\n");
for(i=0;i<MSGSIZE;i++){
printf("%d ",senddata[i]);
}
printf("\n");
*/
}

void lesen() {

int res=0;
// int i=0;
int rdblock=0;
int Fehler=0;

for (rdblock=0;rdblock<MSGSIZE;rdblock++){

commando[0]= 4; //'Adresse setzen ankündigen
commando[1]= 4; //'Adresse übergeben
commando[2]= 2; //start
commando[3]= 7; //'Bytes senden
commando[4]= 1; //'Anzahl
commando[5]= rdblock+10; //Byte
commando[6]= 2; //start
commando[7]= 6; //Bytes lesen
commando[8]= 2; //Anzahl
commando[9]= 3; //stop
commando[10]= 0; //keine weiteren Parameter
res=I2CResetBus();
res=bbI2CZip(SDA,commando,11,puffer,12);
res=I2CResetBus();

if (res==0){
if (puffer[0]==rdblock){
empfdata[rdblock]=puffer[1];
Fehler=0;
}else{
printf("E Falsche Blocknummer. Erwartet: %d, bekommen: %d, Wert: %d\n",rdblock,puffer[0],puffer[1]);
Fehler++;
rdblock--;
if (Fehler==10){
break;
}
}
}else{
printf("E Fehler beim Blockeinlesen. Block: %d\n",rdblock);
Fehler++;
rdblock--;
if (Fehler==10){
break;
}
}
usleep(PAUSEN);
}

printf("Empfangen:\n");
/* for(i=0;i<MSGSIZE;i++){
printf("%d ",empfdata[i]);
}
printf("\n");
*/
}

int vergleichen()
{
unsigned int i=0;
int ret=0;
for (i=0;i<MSGSIZE;i++){
if (empfdata[i]!=senddata[i]){
ret=-1;
break;
}
}
return ret;
}

int main(int argc, char **argv)
{
int res=0;
int i=0;
long dg=1;
long maxdg=0;
unsigned int Fehler=0;

struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);

if (gpioInitialise() < 0)
{
printf("Fehler beim Initialisieren von gpio!");
gpioTerminate();
}else{
res=bbI2COpen(SDA,SCL,TAKT);
res=res+gpioSetMode(SDA, PI_INPUT); // Set SDA as input.
res=res+gpioSetMode(SCL, PI_INPUT); // Set SDA as input.
res=res+gpioSetPullUpDown(SDA, PI_PUD_UP); // Sets SDA pull-up.
res=res+gpioSetPullUpDown(SCL, PI_PUD_UP); // Sets SDA pull-up.

if(res==0){
printf("\n\n\nStarte I2C-Test\n\n");
while (!done)
{
srand(time(NULL));
for(i=0;i<MSGSIZE;i++){
senddata[i]=rand() % 255;
}
schreiben();
usleep(5000);
lesen();
usleep(5000);
if (vergleichen()==0){
printf("Daten OK %ld (%ld)\n",dg,maxdg);
Fehler=0;
dg++;
}else{
printf("***************************** Daten fehlerhaft %ld *****************************\n",dg);
Fehler++;
dg=0;
if (dg>maxdg){
maxdg=dg;
}
sleep(1);
if (Fehler==100){
break;
}
}
}
}else{
printf("E Fehler beim Oeffnen\n");
}
}
res=bbI2CClose(SDA);

if (res!=0){
printf("E Fehler beim Schliessen: %d\n", res);
}else{
printf("E Schliessen OK\n");
}

gpioTerminate();

return 0;
}



Mein Fazit:
Ich bleibe bei UART.

HaWe
14.02.2016, 17:59
hallo,
da hast du es ja immerhin ein ganz gewaltiges Stück weiter geschafft als ich! :)

Danke die aber ganz herzlich für dein Engagement und deine ganzen Posts, schon an deinen letzten Codes kann man noch ein Riesen Stück lernen! :cool:

Gruß
Helmut

peterfido
14.02.2016, 18:32
Hallo,

Danke. Ich lass die Codes mal drin, obwohl nicht optimiert und aufgeräumt.

Meinem LA nach scheint der MEGA bzw. der Wire-Code vom ARDUINO Slave mindestens ein bestimmtes Problem nicht zu erkennen und abzufangen. Evtl. läuft es ohne Pegelwandler stabiler.? Das habe ich nicht mehr probiert.

Der BitBang-Code eignet sich gut, um die Toleranz des ARDUINO-Codes, bzw. des MEGA seiner TWI-Einheit auszutesten. Wenn man sich die Bytes anzeigen lässt, indem man den auskommentierten Code wieder aktiviert, dann liegt bei einem Takt von 100.000 oft nur ein Bit von den 240 Bytes quer. Spielt man mit dem Taktwert, dann steigt die Fehlerquote. Man könnte noch einen langsameren Takt probieren, wenn der ARDUINO-Code das unterstützt. Die weiter Oben erwähnten Flanken kann ich ohne Oszi leider nicht analysieren.

Beim Testen kam mir die Ausgabe vom ARDUINO-MEGA etwas verzögert vor. Kann aber auch an den vielen Bytes liegen. Auch möglich, dass da Interrupts zwischen funken. Da wird viel von der Wire-Bibliothek gemacht. Da das wohl seit 10 Jahren unverändert ist, kann man entweder nicht weiter optimieren oder es hat noch keiner wirklich für Dauereinsätze gebraucht. Im ARDUINO-Forum habe ich nicht gestöbert.

Interessant wäre der Bascom-Slave Code. Allerdings kostet die Bibliothek extra. Das macht für einen reinen kurzen Test für mich keinen Sinn. Oder halt die Datenblätter durchstöbern und selbst was programmieren.

peterfido
15.02.2016, 17:36
Hallo,

es geht nur zuverlässig mit der BitBang-Methode.

Folgende Codes laufen bei mir seit einiger Zeit fehlerfrei durch:

MEGA


// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.
//

#include <Wire.h>

#define REGSIZE 240

byte rspeicher[REGSIZE];
byte wspeicher[REGSIZE];
byte puffer[5];
byte Register=1;
byte block=0;
byte pos=0;
byte fertig=0;
long dg=0;
long timeout=0;

void setup() {
Wire.begin(4); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event
Serial.begin(57600); // start serial for output

Serial.println();
Serial.println("Starte I2C-Test");
}


byte chksum(byte arr[], byte anzahl)
{
byte i;
byte sum=0;

for(i = 0; i < anzahl; i++){
sum+=arr[i];
}
return sum;
}


void loop() {
byte i=0;
delay(100);
timeout++;
if (timeout==90){
timeout=0;
Wire.begin(4);
Serial.println("TimeOut!");
dg=0;
}


if (fertig !=0){
fertig=0;
timeout=0;
dg++;
Serial.println(dg);

for (i=0;i<REGSIZE;i++){
Serial.print(rspeicher[i]);
Serial.print (" ");
}
Serial.println();
}
}

void TWIRESET(){
Wire.begin(4);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
byte x[4];
byte i;
if(howMany == 4){
for (i=0;i<4;i++){
x[i]=Wire.read();
Serial.print (x[i]);
Serial.print (" ");
}
if (x[0]==137){
if (chksum(x,3)==x[3]){
if (x[1]<REGSIZE){
block=x[1];
rspeicher[block]=x[2];
wspeicher[block]=rspeicher[block];
}
if (x[1]==REGSIZE-1){
fertig=1;
}
Serial.println(" - Summe OK");
}else{
Serial.println(" - Summe fehlerhaft");
}
}
}else{
if (howMany==2){
for (i=0;i<2;i++){
x[i]=Wire.read();
if (x[0]==87 && x[1]==56){
TWIRESET();
}
}
}else{
Serial.print ("Anzahl Daten: ");
Serial.println(howMany);
while (0 < Wire.available()) { //überflüssiges lesen
x[4]=Wire.read();
}
}
}
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
byte i;

puffer[0]=block;
puffer[1]=wspeicher[block];
puffer[2]=chksum(puffer,2);
Wire.write(puffer,3);
for (i=0;i<3;i++){
Serial.print (puffer[i]);
Serial.print (" ");
}
Serial.println();


}


Raspi:

// gcc -Wall -pthread -o /var/scripte/bbi2cmaster1012 /var/scripte/bbi2cmaster1012.c -lpigpio -lrt
// /var/scripte/bbi2cmaster1012
//I2C mit pipgio
//peterfido
//V1.012
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pigpio.h>

#define SDA 2
#define SCL 3
#define TAKT 100000
#define PAUSEN 5000
#define ADDRESS 0x04
#define MSGSIZE 240



char empfdata[MSGSIZE]; //
char senddata[MSGSIZE];
char commando[20];
char puffer[12];
unsigned int ARDUPOS=0;

unsigned int laenge=0;

volatile sig_atomic_t done = 0;

void term(int signum)
{
done = 1;
}

int I2CResetBus(void)
{
char i;
int res=0;
if(gpioRead(SDA) && gpioRead(SCL)) {
return 0;
}
gpioSetMode(SCL, PI_INPUT);
gpioSetMode(SDA, PI_INPUT);
gpioSetPullUpDown(SDA, PI_PUD_UP); // Sets SDA pull-up.
gpioSetPullUpDown(SCL, PI_PUD_UP); // Sets SDA pull-up.
usleep(50);
if(!gpioRead(SCL)) {
return -1; /* SCL wird extern auf Low gehalten, nix zu machen */
}
for(i = 0; i<9; i++) {
gpioSetMode(SCL, PI_OUTPUT);
gpioWrite(SCL, 0);
usleep(50);
gpioSetMode(SCL, PI_INPUT);
gpioSetPullUpDown(SCL, PI_PUD_UP); // Sets SDA pull-up.
usleep(50);
if(gpioRead(SDA)) {
break; /* SDA ist high STOP */
}
} /* for */
if(!gpioRead(SDA)) {
return -1;
}
commando[0]= 3; //stop
commando[1]= 0; // Fertig
res=bbI2CZip(SDA,commando,2,NULL,0);
if (res!=0){
printf("Fehler beim Reset!\n");
}
if(gpioRead(SDA) && gpioRead(SCL)){
return 0;
}else{
return -1;
}
}

char chksum(char arr[], int anzahl)
{
int i;
char sum=0;

for(i = 0; i < anzahl; i++){
sum+=arr[i];
}
return sum;

}

int syncen() {

int erg=0;
int res=0;
int i=0;

commando[0]= 4; //'Adresse setzen ankündigen
commando[1]= 4; //'Adresse übergeben
commando[2]= 2; //start
commando[3]= 7; //'Bytes senden
commando[4]= 4; //'Anzahl
commando[5]= 137; //Position
commando[6]= ARDUPOS; //Position
commando[7]= senddata[ARDUPOS]; //Position
commando[8]= chksum(&commando[5],3); //Position
commando[9]= 3; //stop
commando[10]= 0; //keine weiteren Parameter

printf("Gesendet: ");
for(i=6;i<8;i++){
printf("%d ",commando[i]);
}
printf("\n");


res=I2CResetBus();
res=bbI2CZip(SDA,commando,20,puffer,12);
usleep(50000);
commando[0]= 4; //'Adresse setzen ankündigen
commando[1]= 4; //'Adresse übergeben
commando[2]= 2; //start
commando[3]= 6; //Bytes lesen
commando[4]= 3; //Anzahl
commando[5]= 3; //stop
commando[6]= 0; //keine weiteren Parameter
res=I2CResetBus();
res=bbI2CZip(SDA,commando,20,puffer,12);

printf("Empfangen:");
for(i=0;i<2;i++){
printf("%d ",puffer[i]);
}
if (puffer[2] == chksum(puffer,2)){
printf(" - Summe OK");
}else{
printf(" - Summe fehlerhaft %d",chksum(puffer,2));

}
if (res==3){
if (puffer[0]==ARDUPOS && puffer[2] == chksum(puffer,2)){
empfdata[ARDUPOS]=puffer[1];
erg=0;
}else{
printf(" - E Falsche Blocknummer. Erwartet: %d, bekommen: %d, Wert: %d\n",ARDUPOS,puffer[0],puffer[1]);
erg=1;
}
}else{
printf(" - E Fehler beim Blockeinlesen. Block: %d, Fehler: %d\n",ARDUPOS,res);
erg=1;
}
return erg;
}

void ARDURESET(){
commando[0]= 4; //'Adresse setzen ankündigen
commando[1]= 4; //'Adresse übergeben
commando[2]= 2; //start
commando[3]= 7; //'Bytes senden
commando[4]= 2; //'Anzahl
commando[5]= 87; //RESET-Sequenz
commando[6]= 56; //RESET-Sequenz
commando[7]= 3; //stop
commando[8]= 0; //keine weiteren Parameter
I2CResetBus();
bbI2CZip(SDA,commando,20,NULL,0);
usleep(50000);
}

int main(int argc, char **argv)
{
int res=0;
long dg=1;
long maxdg=0;
unsigned int Fehler=0;

struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);

if (gpioInitialise() < 0)
{
printf("Fehler beim Initialisieren von gpio!");
gpioTerminate();
}else{
res=bbI2COpen(SDA,SCL,TAKT);
res=res+gpioSetMode(SDA, PI_INPUT); // Set SDA as input.
res=res+gpioSetMode(SCL, PI_INPUT); // Set SDA as input.
res=res+gpioSetPullUpDown(SDA, PI_PUD_UP); // Sets SDA pull-up.
res=res+gpioSetPullUpDown(SCL, PI_PUD_UP); // Sets SDA pull-up.
srand(time(NULL));
if(res==0){
printf("\n\n\nStarte I2C-Test\n\n");
while (!done)
{

senddata[ARDUPOS]=rand() % 255;
res=syncen();

if (senddata[ARDUPOS]==empfdata[ARDUPOS]){
printf(" - Daten OK %ld (%ld)\n",dg,maxdg);
Fehler=0;
dg++;
}else{
printf(" - Daten fehlerhaft ****************************************** %ld \n",dg);
// ARDURESET();
Fehler++;
dg=0;
if (dg>maxdg){
maxdg=dg;
}

if (Fehler==100){
break;
}
}

if (res==0){
ARDUPOS++;
if (ARDUPOS >= MSGSIZE){
ARDUPOS=0;
//usleep(500000);//Dem ARDUINO Zeit für die Anzeige geben
//sleep(2);//Dem ARDUINO Zeit für die Anzeige geben
}

}

usleep(5000);
}
}else{
printf("E Fehler beim Oeffnen\n");
}
}
res=bbI2CClose(SDA);

if (res!=0){
printf("E Fehler beim Schliessen: %d\n", res);
}else{
printf("E Schliessen OK\n");
}

gpioTerminate();

return 0;
}




Es läuft hier mit Pegelwandler.

Es wird in der Sub 'Sync' (Evtl. sollte diese noch einen anderen Namen bekommen. Der Name Sync ist bei HardwareI2C schon belegt...) bei jedem Aufruf nur ein DatenByte geschrieben und gelesen. Es gibt ein Startbyte und eine Prüfsumme um Kommunikationsfehler zu erkennen.

Wie es sich mit Interrupts auf dem MEGA verträgt, habe ich nicht getestet. Ob die TWIRESET Sub auf dem Mega immer zuverlässig läuft, kann ich nicht sagen. Evtl. kann man die Pausen verkürzen, wenn der MEGA nix weiter zu tun hat oder sie müssen verlängert werden, wenn Fehler z.B. wegen vieler Interrupts auftreten.


Hardware I2C verträgt sich mit dem (meinem) ARDUINO MEGA irgendwie nicht.

HaWe
16.02.2016, 15:09
hallo,
danke für's Update!

das ist aber jetzt noch immer nicht mein ursprünglicher i2c-Job mit je 32 bytes vom Raspi aus abwechselnd vom Arduino lesen / an Arduino schreiben, mit je 10ms delay dazwischen, oder?

Mein Arduino-Slave code muss unbedingt so bleiben wie er war!


// Arduino code to send/receive byte arrays
// Arduino as an I2C slave
//
// ver. 0.002b


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
#define MSGSIZE 32
byte recvarray[MSGSIZE]; // 0=0xff; 1=chksum; ...data...; MSGSIZE-1=SLAVE_ADDRESS
byte sendarray[MSGSIZE];

volatile int8_t flag=0;


//================================================== ===================================
//================================================== ===================================
void setup() {
int32_t i=0;

// Serial terminal window
i=115200;
Serial.begin(i);
Serial.print("Serial started, baud=");
Serial.println(i);

// Wire (i2c)
Wire.begin(SLAVE_ADDRESS); // start Arduino as a I2C slave, addr=0x04 (7-bit coded)

Wire.onReceive(receiveData ); // event when master array is sent
Wire.onRequest(sendData ); // event when master requests array to read

memset(sendarray, 0, sizeof(sendarray) ); // init send- and recv arrays
memset(recvarray, 0, sizeof(recvarray) );

Serial.print("I2C init: my slave address= ");
Serial.println(SLAVE_ADDRESS);
Serial.println("I2C init: done.");
Serial.println();

Serial.println("setup(): done.");

}


//================================================== ===================================


uint8_t calcchecksum(uint8_t array[]) {
int32_t sum=0;
for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
return (sum & 0x00ff);
}

//================================================== ===================================

void loop()
{
char sbuf[128];

Serial.println(); Serial.println();

// do something with the received data
// and then do something to build the sendarray [3]...[MSG_SIZE-2]

if (flag==1) {
//debug
sendarray[4] +=1;
}

sendarray[0] = 0xff; // 0 = start: 0xff == msg start flag
sendarray[2] = flag; // 2 = send back msg error flag
sendarray[MSGSIZE-1] = SLAVE_ADDRESS; // end of array: ID check

sendarray[1] = calcchecksum(sendarray); // 1 = calc new chksum
flag=0;

// debug output
sprintf(sbuf, "Sendarr[4]=%4d, [5]=%4d, Recvarr[4]=%4d, [5]=%4d",
sendarray[4], sendarray[5], recvarray[4], recvarray[5]) ;
Serial.println(sbuf);

delay(1); // short break for the cpu and the bus
}


//================================================== ===================================

void receiveData(int byteCount) {
int32_t i;
byte val;

while(Wire.available()<MSGSIZE) ; // wait for all bytes to complete
i=0; // init counter var
while(Wire.available()&& (i<MSGSIZE) ) // read all recv array bytes
{
val=Wire.read();
recvarray[i++]=val;
}

// check for transmission error
if( (recvarray[0] == 0xff)
&& (recvarray[1] == calcchecksum(recvarray))
&& (recvarray[MSGSIZE-1] == SLAVE_ADDRESS ) )
flag=1; // data ok
else
flag=127; // data faulty => handle rcv-error => flag =127
}

//================================================== ===================================

void sendData(){
// Wire.write writes data from a slave device in response to a request from a master
Wire.write(sendarray, MSGSIZE); // send own byte array back to master..

peterfido
16.02.2016, 16:28
Hallo,

nein. Das ist ein alternatives Protokoll. Getestet mit 240 Nutzbytes. Das kannst Du an Deine Zwecke anpassen und testen. Ich hatte es so verstanden, dass 30 Bytes nicht ausreichen.

Evtl. läuft es mit 32 Bytes immer noch fehlerfrei. Wobei Du die Slave-Adresse nicht mitschicken brauchst, da er ja nur auf seine Slave-Adresse reagiert bzw. reagieren sollte. Aufpassen musst Du darauf, dass nach der Prüfsummenbildung die Bytes nicht mehr verändert werden. Das ist bei dem Testcode nicht der Fall, kann später, wenn der MEGA ein paar Bytes mit anderen ICs austauscht, Zeitprobleme mitbringen. Wenn alles bis zur nächsten senddata-Bildung noch zwischengespeichert werden muss. Da lässt sich Zeit sparen, wenn die Prüfsumme gleich beim Array-Zusammenbau mit berechnet wird.

Ich habe mich mal über den DUE informiert. Dieser spielt in einer ganz anderen Liga als der MEGA. Wenn Du für den ARDUINO ein Display vorgesehen hast, werden die 10 ms-Lücken zwischen I2C-Datenaustausch für Display, die Ansteuerung weiterer IC´s über evtl. UART ISP und I2C sowie Speicherkopiererei und evtl. TimerInterrupts bei den 16MHz des MEGA etwas knapp.

Ich mache es immer umgekehrt. Der Raspi ist der Kommunikative und dient dem AVR per UART als Gateway zu allen sonstiges Gerätchen. Vor Allem Ethernet bzw. WLAN fehlen den AVRs. Leider auch dem DUE, obwohl es der Mikrocontroller quasi mitbringt. Dann übernimmt der Raspi neben dem Webinterface oft noch Lautsprecher und die farbige Anzeige auf Bilderrahmen über lcd4linux per USB.

Deine Projekt kenne ich nicht und weiß nicht, was da zeitkritisches vor sich gehen soll, bzw. warum das Timing so brisant ist.

Das schnellste ist ganz klar SPI. Danach kommt UART, wenn man ein Baudratenquartz hat, danach dann I2C. Parallel ist theoretisch 8 mal so schnell wie UART, wird aber von der Hardware nicht unterstützt und läuft ohne Puffer nicht ganz so zuverlässig. Benötigt aber auch die meisten PortPins. Bei SPI geht Dein Protokoll aber nicht, da bei jedem Senden auch gleichzeitig empfangen wird.

HaWe
16.02.2016, 18:56
achso - sogar 240 statt 32 Bytes - das ist ntl ein dicker Pluspunkt, und dass das SPI-Display hier ein Zeitproblemwerden könnte, stimmt auch, das habe ich noch gar nicht ausgetestet. Ich wollte die ILI9341_due lib verwenden, die soll angeblich auch mit dem Mega laufen - selber gemacht habe ich es damit aber nicht, nur mit dem Due. Wäre in der Tat ein weiterer Knackpunkt.
Danke nochmal für die Erklärungen und Tipps!

- - - Aktualisiert - - -

es geht im Prinzip darum, Arduinos sowohl als Sensor-Multiplexer als auch für Fernsteuerungen zu nutzen, und darum, gleichzeitig auch noch weitere spezielle I2c und UART-Sensoren an den Raspi anzuschließen (IMU- GPS, RTC - vllt sogar mal nen LIDAR).
UART alleine reicht dazu nicht aus, weil nur ein "slave" angeschlossen werden kann, bei i2c dagegen dutzende am selben Port. Je mehr Geräte am Bus hängen, desto schneller muss aber jedes einzelne Gerät arbeiten und gesteuert werden können.

peterfido
16.02.2016, 19:57
Hallo,

das klingt nach ein paar interessante Aufgaben. IMU, GPS und LIDAR nach einem selbstfahrenden Fahrzeug. Wenn GPS vorhanden ist, kann die RTC wegfallen. Wobei der Raspi ja auch eine Uhr hat. So braucht die RTC nur gelegentlich abgeglichen werden. Der Raspi selbst hat mehrere UARTs. Ein USB-Hub dran und daran ein paar FTDI anschließen. Dutzende I2C Slaves teilen sich die Geschwindigkeit von 100k. Soll der Bus schneller laufen, müssen alle mit der höheren Geschwindigkeit klar kommen.

Bei einem selbst gebauten Protokoll, können an einem UART auch mehrere 'Slaves' hängen. Einfach einen Ring aufbauen. Der Nachteil ist, dass alle Slaves die Daten weiterreichen müssen. Also überall Mikrocontroller dran. Diese können über einen zweiten UART andere Geräte bedienen. Das (mein) Protokoll (an welchem ich nicht weiter arbeite) ist etwas trickreich oder es müssen entsprechend große Buffer verwendet werden. Daher nehme ich lieber die Lösung mit mehreren UARTs.

Deine Idee, I2C zu nutzen, gefällt mir. Mich stören eher meine Testergebnisse. Evtl. arbeite ich da nochmal weiter dran. Dafür muss ich aber erstmal investieren. Evtl. habe ich sogar noch einen 'alten' Raspi irgendwo rum(f)liegen, damit einer mal als Slave dienen kann. Einen DUE-Nachbau plus SPI-Display habe ich mir heute geordert. Während meines Bestellvorgangs ging die Anzahl der Verfügbaren nach unten. Evtl. lesen hier welche mit und kaufen nun ein ;)

Ich selbst habe viel mit AVRs gebaut. Eigene Platinen mit Löten und so. Das mach mir immer weniger Spass. (Brille ab, Brille auf, Lupe,... - Das brauchte ich 'früher' alles nicht) Bei den ARDUINOs reicht zusammenstecken und programmieren. Wobei es mir aktuell mehr ums programmieren (wenn es draußen ungemütlich ist) an sich geht. Allerdings habe ich da auch noch ein paar Windows-Tools in der Pipeline...

HaWe
17.02.2016, 07:44
stimmt, ein selbstfahrendes Fahrzeug, die Idee mit den USB Hubs hatte ich auch schon, gefällt mir aber nicht so gut.
Mein Setup sieht z.Zt.: vor:
1x UART slave für BT Fernbedienung und Telemetrie (USB/FTDI)
1x UART Slave (Mega) für schnelle IOs
1-2x i2c Slave (Dues) für den ganzen Rest, auch für weitere Huckepack-Sensoren auf den Arduinos mit drauf (wschl auch GPS).

GPS indoors hat oft schlechte Verbindung, daher zusätzlich die RTC, und auch WiFi habe ich nicht immer empfangsbereit.
Insgesamt sind für die meisten Sensoren viel bessere und einfachere Arduino-Libs vorhanden als für den Raspi mit seinen ganzen komplizierten device trees, daher will ich die meisten huckepack nehmen (vlt auch den UART-GPS). Der IMU (CMPS11, i2c) muss aber direkt an Raspi-I2c dran wegen Geschwindigkeit für die Lokalisierung (Navigation, Ortung) fusioniert mit der Odometrie und anderen Distanzsensoren, Baken-Peilungen und was auch immer.

Es soll aber vlt schon bald ein Raspi Jessie-Kernel-Update kommen, das besser clock-stretching-veträglich ist (wird offenbar dran gearbeitet, hatte ich oben schon verlinkt). Dann werden die AVRs sicher genauso einfach und problemlos mit wiringPi laufen wie jetzt schon meine Dues, daher brennt es mir nicht ganz so unter den Nägeln mit meinen Megas. Es gibt eh noch unglaublich viel an Vorbereitungen zu tun und zu entwickeln...

ps,
als Display empfehle ich ILI9341-TFTs, denn dafür gibt es die irre schnelle ILI9341_due lib mit 84MHz DMA auf dem SPI - alle anderen sind ein dutzend Mal langsamer:
http://www.mindstormsforum.de/viewtopic.php?f=78&t=8491#p66189
http://marekburiak.github.io/ILI9341_due/
Nachteil: es gibt Inkompatibilitäten mit SD-Libs.


pps
ich habe mir gerade auch einen 2. Raspi 2 Model B bestellt für 40 EUR inkl. Versand - jetzt kann ich besser und einfacher an verschiedenen Baustellen gleichzeitig arbeiten -
einmal für die Fernsteuerung und die Multiplexer, und einmal direkt am Robo für die Motoren und Odometrie-Tests. Was immer noch fehlt, ist sehr viel Zeit dafür....

peterfido
17.02.2016, 15:33
Was immer noch fehlt, ist sehr viel Zeit dafür....

Hallo,

ja, das ist DER Knackpunkt. Als Display habe ich mir eines mit dem ILI9341 bestellt. Mal sehen, wie die 2,2 Zoll so wirken. Wirklich schade finde ich, dass die beim DUE nicht die Ethernet-Schnittstelle rausgeführt haben. Gerade, wo doch IOT DAS Thema überhaupt ist. Und was mir noch fehlt, sind vernünftige, wohnzimmertaugliche Gehäuse mit Aussparungen für Display und vernünftige Tastaturen sowie Platz für Netzteil- oder andere Platinen. Ich mißbrauche oft Radiogehäuse, DVD-Player-Gehäuse usw.

Durch den / die / das also THE pigpio bist Du flexibel und kannst mehrere I2C-Busse fahren. Von Vorteil wäre da noch ein Pausen-Kommando. Der Pi kann recht einfach Multithreading. Da könnte man die Synchronisation mit den ARDUINOs in einem eigenen Thread laufen lassen und blockiert so keine anderen Routinen. GPS hat etwas den Nachteil, dass es kontinuierlich Daten zum Mikrocontroller sendet. Selbst, wenn Du dann UART pufferst, wird bei jedem empfangenen Zeichen kurz ein Interrupt ausgelöst, um es im Puffer abzulegen. Das könnte dem I2C in die Quere kommen. Oder man deaktiviert solange den GPS-UART. Aber da dann immer ein volles GPS-Telegramm zu erhalten, könnte 'tricky' werden.

Also doch lieber an den Raspi. (Oder den DUE. Da fehlt mir aber (noch) die Erfahrung.)

Mxt
18.02.2016, 07:43
Wirklich schade finde ich, dass die beim DUE nicht die Ethernet-Schnittstelle rausgeführt haben. Gerade, wo doch IOT DAS Thema überhaupt ist.
Das muss wohl so sein, um Arduino kompatibel zu bleiben. Da macht man Ethernet halt über ein Shield, weil das immer schon so war. Beim Galileo z.B. simuliert das Linux darauf ein Ethernetshield in Software. So eine Lösung würde den Due sicher zu sehr auslasten.

Schade ist das schon, da hast du Recht. Über Ethernet schaffe ich einige Megabyte pro Sekunde zwischen Raspi und Mikrocontroller.