Go Down

Topic: UDP send/recieve (Read 9 times) previous topic - next topic

Mad Zach

Hi there,

I recently purchased an Arduino ethernet shield w/ SD reader. Right now I'm just trying to send/recieve UDP messages back and forth between max and arduino.

I started by using the UDPSendRecieveString (http://arduino.cc/en/Tutorial/UDPSendReceiveString) code from the arduino tutorials section.

I downloaded the Spi and Udp libraries and believed to have installed them correctly. However, this is the message I get when compliling

o: In function `loop':
undefined reference to `Udp'o: In function `setup':

Any suggestions on the root of this conundrum?

Cheers,
Zach

PaulS

If you use Sketch + Import Library..., can you import the Ethernet and Udp libraries? If so, they are installed in the right place. If not, they are not.

Of course, I would expect that you would get a failure about the inability to include Udp.h and/or Ethernet.h if they were not in the right place.

But, it's the first thing to check.

VilluV

#2
Nov 20, 2010, 10:16 pm Last Edit: Nov 20, 2010, 11:16 pm by villuv Reason: 1
Hi,

Arduino UNO + IDE 0021 running on 64bit Linux: This example compiles OK for me. But I have following problems with it:

Whenever I run it, Udp.available() returns 1024 immediately, without anything actually being sent to that port. Next, the program hangs on Udp.readPacket() call. Serial console displays: "Received packet of size 1016"

I also tried just sending small, constant, udp packets, using Udp.sendPacket(const char[], uint8_t*, uint16_t)
It works well, but occasionally the packet contains just random bytes and is much larger, hundreds of bytes. Looks like buffer gets read from a wrong address. sendPacket method itself reports correct number of bytes sent for those invalid packets.

btw, Should the ReplyBuffer string in that example be zero-terminated to work correctly with that sendPacket method?

Edit: just discovered that invalid packets are sent in bursts of tens of pakets, all by one sendPacket call. Investigating further... (I can upload packet capture + test program if anyone is interested)

robtillaart

Please share the code so we have something to look at. Small typo's can make big difference :)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

VilluV

The first, udp.available(), problem happens with unmodified version of the UdpSendReceiveString example that is bundled with IDE 0021.

I'll post the code for my udp send example when I'll get back home in a couple of hours...

VilluV

#5
Nov 21, 2010, 02:21 pm Last Edit: Nov 21, 2010, 05:57 pm by villuv Reason: 1
OK, here it is, my little pinger...
Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <Udp.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x20, 0xA4 };
byte ip[] = { 192,168,1,177 };
byte remoteIp[] = { 192,168,1,123 };
unsigned int localPort = 8888;
unsigned int remotePort = 8889;

char sendBuffer[] = "ping\0";

unsigned int sentSize = 0;

void setup() {
 Ethernet.begin(mac, ip);
 Udp.begin(localPort);
 Serial.begin(9600);
 delay(100);
}

void loop() {
  sentSize = Udp.sendPacket(sendBuffer, remoteIp, remotePort);
  Serial.print("Bytes sent: ");
  Serial.println(sentSize);
  delay(1000);
}

Ethernet and UDP libs are the ones bundled with 0021.

On receiving end, I'll listen in with netcat:
Code: [Select]
nc -l -u -p 8889

I can see a row or two of "pingpingpingping" as expected, and then couple of pages of trash and then again "pingpingping"... repeat...
Serial console displays "Bytes sent: 4" every second.

[edit]
Packet capture of the problem is downloadable from here: http://byte.ee/udp_send_bug.pcap (74KB)
[/edit]

VilluV

And here is a test case for Udp.available() problem

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <Udp.h>

byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x20, 0xA4};
byte ip[] = {192, 168, 1, 177};
unsigned int localPort = 8888;

byte remoteIp[4];
unsigned int remotePort;

char packetBuffer[64];

void setup() {
 Ethernet.begin(mac, ip);
 Udp.begin(localPort);
 Serial.begin(9600);
 delay(1000);
}

void loop() {
 int bytesAvailable = Udp.available();
 Serial.print("Available bytes: ");
 Serial.println(bytesAvailable);
 while(true);
}


This will always output "Available bytes: 1024" to console, even if the ethernet cable is unplugged.

VilluV

More info about the UDP trash-sending problem. To debug it I added these lines to the end of W5100Class::send_data_processing() method in libraries/Ethernet/utility/w5100.cpp
Code: [Select]

...
    ptr += len;
    writeSnTX_WR(s, ptr);
   [glow] Serial.print("TX_WR=");[/glow]
   [glow]Serial.println(ptr);[/glow]
}


and also a simple println to the buffer wrap-around condition above, because that's where I thought the problem will be. To my surprise, it never gets to the wrap-around. TX_WR register goes from 1028 to 1280, increases nicely by 4 as I'm using 4-byte message. But then after 1280 it will wrap back to 1028 and at that point the trash-packets are sent.

I'm out of ideas here, it starts to look like a hardware problem... :(

VilluV

Update:
Probably not a harware problem. I was able to test the same program with identical etherShield and it behaved the same. Problem seems to be reading of the Sn_TX_WR register: its internal value seems to be 0 at startup, but somehow it gets read out as 1024...  [smiley=shocked.gif]

PaulS

Is it possible to just subtract 1024, if the value is over 1024?

VilluV

I'll check it out in the evening after my work.

I'll first verify that the register value reading part (preprocessor generated functions in w5100.h and address calculations) are working correctly. Because the symptom is similar with Udp.available() problem: it reports 1024 if it should report 0.

There's one bit error somewhere out there and I'm pretty sure I'll hunt it down!  [smiley=evil.gif]

VilluV

#11
Nov 24, 2010, 10:16 pm Last Edit: Nov 24, 2010, 10:27 pm by villuv Reason: 1
Some kind of timing problem, ladies & gentelmen?

I modified w5100.h so that I wrote out read/write functions for Sn_TX_WR register:

Code: [Select]

static void writeSnTX_WR(SOCKET _s, uint16_t _data) {
   writeSn(_s, 0x0024, _data >> 8);
   writeSn(_s, 0x0025, _data & 0xFF);
}

static uint16_t readSnTX_WR(SOCKET _s) {
   uint16_t res = readSn(_s, 0x0024);
   res = (res << 8) + readSn(_s, 0x0025);
   return res;
}


calling readSnTX_WR(0) returns 1024

but when I put in some debugging statements:

Code: [Select]

static uint16_t readSnTX_WR(SOCKET _s) {
   uint16_t res = readSn(_s, 0x0024);
[glow]    Serial.print("RES1 "); Serial.println(res, HEX);[/glow]
   res = (res << 8) + readSn(_s, 0x0025);
[glow]    Serial.print("RES2 "); Serial.println(res, HEX);[/glow]
   return res;
}


It returns nicely 0 (and of course RES1 and RES2 outputs are both 0 too..

But then again, as the invalid byte gets read before valid one (0x0400) how is it affected by these println-s at all?!?

go figure...

Update:
Also works if I replace println-s there with delay(100);
I also made readSn() method public and called it directly in setup() function, right after initializing Ethernet lib:
Code: [Select]

uint8_t S0_TX_WR_HI = W5100.readSn(0, 0x24);
uint8_t S0_TX_WR_LO = W5100.readSn(0, 0x25);

... and if called this way, both bytes are zero as they should. But why timing doesn't matter in this case?

VilluV

#12
Nov 25, 2010, 12:27 am Last Edit: Nov 25, 2010, 01:01 am by villuv Reason: 1
original method (doesn't work)

Code: [Select]

static uint16_t readSnTX_WR(SOCKET _s) {
   uint16_t res = readSn(_s, 0x0024);
   res = (res << 8) + readSn(_s, 0x0025);
   return res;
}

000003f4 <_ZN10W5100Class11readSnTX_WREh>:
3f4:   ef 92           push    r14
3f6:   ff 92           push    r15
3f8:   1f 93           push    r17
3fa:   cf 93           push    r28
3fc:   df 93           push    r29
3fe:   18 2f           mov     r17, r24        ;
400:   64 e2           ldi     r22, 0x24       ; 36
402:   70 e0           ldi     r23, 0x00       ; 0
404:   0e 94 ab 00     call    0x156   ; 0x156 <_ZN10W5100Class6readSnEhj>
[glow] 408:   80 e0           ldi     r24, 0x00       ; 0     !!!1[/glow]
[glow] 40a:   ec 01           movw    r28, r24        ; !!!2[/glow]
40c:   81 2f           mov     r24, r17
40e:   65 e2           ldi     r22, 0x25       ; 37
410:   70 e0           ldi     r23, 0x00       ; 0
412:   0e 94 ab 00     call    0x156   ; 0x156 <_ZN10W5100Class6readSnEhj>
416:   c8 0f           add     r28, r24
418:   d1 1d           adc     r29, r1
41a:   ce 01           movw    r24, r28
41c:   df 91           pop     r29
41e:   cf 91           pop     r28
420:   1f 91           pop     r17
422:   ff 90           pop     r15
424:   ef 90           pop     r14
426:   08 95           ret


As I understand, readSn method returns its 8-bit result value in r24, but

  • [glow]!!!1[/glow] - actual result of high-byte gets always zeroed!
  • [glow]!!!2[/glow] - r25 gets written into r29, which has undefined value at this point, and it ends up in the high byte of the result!

Compiler messes up when trying to write 8-bit method return value to 16-bit variable??!?

Slightly rewritten, but equivalent method which works:

Code: [Select]

static uint16_t readSnTX_WR(SOCKET _s) {
   uint8_t hi = readSn(_s, 0x0024);
   uint8_t lo = readSn(_s, 0x0025);
   uint16_t res = hi;
   res = (res << 8) + lo;
   return res;
}

000003f4 <_ZN10W5100Class11readSnTX_WREh>:
3f4:   0f 93           push    r16
3f6:   1f 93           push    r17
3f8:   18 2f           mov     r17, r24      
3fa:   64 e2           ldi     r22, 0x24       ; 36
3fc:   70 e0           ldi     r23, 0x00       ; 0
3fe:   0e 94 ab 00     call    0x156   ; 0x156 <_ZN10W5100Class6readSnEhj>
402:   08 2f           mov     r16, r24
404:   81 2f           mov     r24, r17
406:   65 e2           ldi     r22, 0x25       ; 37
408:   70 e0           ldi     r23, 0x00       ; 0
40a:   0e 94 ab 00     call    0x156   ; 0x156 <_ZN10W5100Class6readSnEhj>
40e:   30 2f           mov     r19, r16
410:   20 e0           ldi     r18, 0x00       ; 0
412:   28 0f           add     r18, r24
414:   31 1d           adc     r19, r1
416:   c9 01           movw    r24, r18
418:   1f 91           pop     r17
41a:   0f 91           pop     r16
41c:   08 95           ret


... assembly looks correct and it's even smaller.


[edit]Added analysis[/edit]

VilluV

Hi,

Could someone test what this code outputs for you, please (and what version of gcc-avr you're using)

And don't have anything connected to pin 4....

Code: [Select]

// trick the compiler not to optimize everything out
uint8_t getTheByte(uint8_t pin) {
 uint8_t res = digitalRead(pin); // should return 0
 res++; // increment it to 1
 return res;
}

uint16_t getTheInt(uint8_t pin) {
 uint16_t res = getTheByte(pin);
 res = (res << 8) + getTheByte(pin);
 return res;
}

void setup() {
 delay(3000); // just in case for the UNO serial problem...
 Serial.begin(9600);
 uint16_t value = getTheInt(4);
 Serial.println(value, HEX);   // should write 101
}

void loop() {
  while (true) {
    delay(2000);
  }
}


It should display 101, but for me it displays 1 as the upper byte gets "accidentally" zeroed out.

thanks!

robtillaart

Runned the sketch in IDE 0021 and the output was 101

"C:\Program Files (x86)\arduino-0021\hardware\tools\avr\bin\avr-gcc.exe" --version
avr-gcc.exe (WinAVR 20081205) 4.3.2



Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up