Stellaris ARM Cortex M3 is a
product of Texas Instruments (TI). Unlike
powerful DSP’s or floating point microcontrollers, this microcontroller is not
suitable for Power Electronics applications control system. However, due to its
communication features it can be a very good monitoring processor. The
microcontroller has an Ethernet module and its evaluation kit has already
mounted Ethernet connector. I am using Stellaris ARM Cortex M3 for monitoring
purposes in one of my Active Power Filter project. The microcontroller has the
analog inputs for necessary channels like active filter current, line voltage,
dc link voltage and heatsink temperatures. These analog information is
converted to digital and sent to the Human Machine Interface (HMI) of automation
system via Ethernet communication. This is the duty to be conducted by this
microcontroller. In this article, I will try to explain the methods to conduct
this applications with basic TCP/IP protocol and explain ,in detail, my
solution.
TI provides lots of sample codes
and manuals for different applications. One of these sample codes and manuals
is about TCP/IP protocol. There are two modules served for this purpose which
are generated by Adam Dunkels namely uIP (micro IP) and lwIP (lightweight IP).
One can use these methods to communicate to any device using Ethernet communication.
uIP is smaller in size than lwIP. It contains basic
functions to establish or finish the connection and sending or receiving data.
uIP is not a complex structure thus; it is better for simple applications. lwIP
, on the other hand, has more complex structure than uIP but its features are a
bit more developed. Actually, for basic communication purposes, one can use uIP
easily for Ethernet communications.
My solution ,on the other hand, uses the
open-sourced uIP stack ,however; I add my functions for establishing, finishing
connections and receiving or sending data routins. By this way, I form a code
that listens any of the device that requires connection establishment and sends
the data immediately after receiving data from the host.
The physical connection is started when the host sends a broadcast in ARP (Adress Resolution Protocol), stating its own MAC adress, IP and the destination IP adress. If our microcontroller has the same IP adress of host requires, our system sends an answer stating its own MAC address and IP in ARP. After this process, now the host knows our IP address. To establish the connection the host sends a SYN flaged packet in order to initialize the sequence number and the rules of connection (like window size, protocol number IPv4, TCP protocol and its listening port). Our system turns an answer of SYN/ACK packet to understand the rules and port numberof the host. Finally, the host send and ACK packet to show that it succesfully establish the connection and ready to transfer data with the stated rules. After the synchronisation is handled, the host sends a data whenever it wants using the PSH,ACK flaged packet. This packet contains the data to be transfered and requires an acknowledge that the data is reached correctly. Once, our system get the PSH,ACK flaged packet, we immediately send an ACK packet to say that we succesfully get the data. After we successfully receive the data we send our information to the host using PSH,ACK flaged packet. Similarly, it is expected that the host sends ACK packet when it reads our information. The data sending cycle continues until the host finishes or reset the connection. To finish the connection, host sends FIN,ACK packet for healty ending of connection or RST,ACK packet if it needs to force the connection to end.
My code for handling all these TCP/IP communication procedure is as stated below.
//
//
HANDLING THE TCP/IP AND ARP PROTOCOLS - EMRE DURNA
//
long
EthernetPacketGetDMA(unsigned
long ulBase, unsigned char *pucBuf, long lBufLen)
{
int k,freq_index;
long len;
int Data_len = 0;
// Check the arguments.
ASSERT(ulBase == ETH_BASE);
ASSERT(pucBuf != 0);
ASSERT(lBufLen > 0);
len=ROM_EthernetPacketGetNonBlocking(ulBase, pucBuf, lBufLen); // get the received packet on pointer pucBuf
// ARP packets handled here
if(*(pucBuf+12)==0x08
&& *(pucBuf+13)==0x06 && *(pucBuf+41)==DEFAULT_IPADDR3)
{
for(k=0;k<6;k++)
{ARP_SEND[k]
= *(pucBuf+k+6); // Dest MAC
ARP_SEND[k+32]
= *(pucBuf+k+6); // target mac }
for(k=0;k<4;k++)
{ARP_SEND[k+38]=*(pucBuf+k+28);
}
EthernetPacketPutDMA(ETH_BASE,ARP_SEND,42);
}
// IP packets handled here
if(*(pucBuf+12)==0x08
&& *(pucBuf+13)==0x00) // IP packets here
{
for(k=0;k<6;k++) // destination MAC
TCP_SEND[k]=*(pucBuf+k+6);
if(TCP_SEND[19]==0xFF) // identification increments every send
procedure
{TCP_SEND[19]=0x00;
if(TCP_SEND[18]==0xFF)
TCP_SEND[18]=0x00;
else
TCP_SEND[18]++;
}
else
TCP_SEND[19]++;
for(k=0;k<4;k++)
TCP_SEND[k+30]=*(pucBuf+k+26); // Destination IP
TCP_SEND[36]=*(pucBuf+34); // Destination Port
TCP_SEND[37]=*(pucBuf+35);
TCP_SEND[46]=0x50;
// header length
///****** SYN packets here
if(*(pucBuf+47)==0x02) //SYN packets
{ for(k=0;k<4;k++)
{TCP_SEND[k+42]=*(pucBuf+38+k); }
TCP_SEND[38]=0x00;
TCP_SEND[39]=0xDE;
TCP_SEND[40]=0xAB;
TCP_SEND[41]=0x32;
TCP_SEND[45]++; // Ack num + 1
TCP_SEND[47]=0x12; // SYN,ACK
TCP_SEND[48]=*(pucBuf+48); // window size
TCP_SEND[49]=*(pucBuf+49);
TCP_SEND[52]=0x00;
TCP_SEND[53]=0x00;
if(len>54)
{TCP_SEND[17]=*(pucBuf+17);
TCP_SEND[46]=*(pucBuf+46); // header length
for(k=54;k<len;k++) // options
TCP_SEND[k]=*(pucBuf+k);}
Add_CheckSum(len);
EthernetPacketPutDMA(ETH_BASE,TCP_SEND,len);
}// end SYN
////////*** ACK packets here
else if (*(pucBuf+47)==0x10)
{ //
data transfer cycle is ended. Nothing is necessary to do
}// end ACK
////////*** PSH,ACK packets here
else if (*(pucBuf+47)==0x18)
{Data_len = *(pucBuf+17)-0x28; // how many
bytes of data are received?
TCP_SEND[17]=0x28;
for(k=0;k<4;k++)
{TCP_SEND[k+38] = *(pucBuf+k+42);
TCP_SEND[k+42] = *(pucBuf+38+k); }
TCP_SEND[45]
+= Data_len;
if(TCP_SEND[45]<Data_len)
{TCP_SEND[44]++;
if(TCP_SEND[44]==0x00)
{TCP_SEND[43]++;
if(TCP_SEND[43]==0x00)
TCP_SEND[42]++;
}
}
TCP_SEND[46] = 0x50;
TCP_SEND[47] = 0x10; // ACK
TCP_SEND[48]=*(pucBuf+48); // window size
TCP_SEND[49]=*(pucBuf+49);
Add_CheckSum(54);
EthernetPacketPutDMA(ETH_BASE,TCP_SEND,54);
if(*(pucBuf+55)
== 0xCC)
ETH_COMM_CORRECT++;
if(*(pucBuf+55)==0xAA
&& Data_len == 22)
{for(k=0;k<22;k++)
receiveArray[k]
= *(pucBuf+54+k); }
sendArray[0] = 0x02;
// ID2
sendArray[1] = 0xBB;
// ack
for(k=2;k<22;k++)
sendArray[k]
= receiveArray[k];
sendArray[22]
= (mALARM >> 8) & 0x00FF; //
alarm high byte
sendArray[23]
= mALARM& 0x00FF; //alarm
low byte
sendArray[24]
= (_IQ7int(Vdc_mean) >> 8) & 0x00FF;
//dc link voltage
sendArray[25]
= _IQ7int(Vdc_mean) & 0x00FF;
GP_CURRENT
= _IQ7int(Iha_mean);
GP_CURRENT
= isqrt(GP_CURRENT);
sendArray[26]
= (GP_CURRENT >> 8) & 0x00FF;
// active filter current
sendArray[27]
= GP_CURRENT& 0x00FF;
freq_index
= 0;
for(k=28;k<108;k=k+4) // send frequency values
{
sendArray[k]
= (freq[freq_index][0]>>8) & 0x00FF;
sendArray[k+1]
= freq[freq_index][0] & 0x00FF;
sendArray[k+2]
= (freq[freq_index][1]>>8) & 0x00FF;
sendArray[k+3]
= freq[freq_index][1] & 0x00FF;
freq_index++;
}
sendArray[108]
= T1_int; // send temperatures
sendArray[109]
= T2_int;
sendArray[110]
= T3_int;
Send_Data_PLC(sendArray,111);
}//
end PSH,ACK
////********** FIN,ACK packets here
else if(*(pucBuf+47)==0x11)
{TCP_SEND[17]=0x28;
for(k=0;k<4;k++)
{TCP_SEND[k+38] = *(pucBuf+k+42);
TCP_SEND[k+42] = *(pucBuf+38+k); }
TCP_SEND[45]
+= 1;
if(TCP_SEND[45]==0x00)
{TCP_SEND[44]++;
if(TCP_SEND[44]==0x00)
{TCP_SEND[43]++;
if(TCP_SEND[43]==0x00)
TCP_SEND[42]++; }
}
TCP_SEND[46] = 0x50;
TCP_SEND[47] = 0x10; // ACK
TCP_SEND[48]=*(pucBuf+48); // window size
TCP_SEND[49]=*(pucBuf+49);
Add_CheckSum(54);
EthernetPacketPutDMA(ETH_BASE,TCP_SEND,54);
TCP_SEND[47]
= 0x11; // FIN,ACK
Add_CheckSum(54);
EthernetPacketPutDMA(ETH_BASE,TCP_SEND,54);
}// end FIN,ACK
}
// end else if
// Clear the RX Packet event and
re-enable RX Packet interrupts.
//
if(HWREGBITW(&g_ulFlags, FLAG_RXPKT)
== 1)
{
HWREGBITW(&g_ulFlags,
FLAG_RXPKT) = 0;
ROM_EthernetIntEnable(ETH_BASE,
ETH_INT_RX);
}
return len;
}//
end function
For the whole source code and detailed information please contact me.
Emre,
ReplyDeleteThanks for sharing your code. Don't you use any protocol on top of TCP/IP to communicate with HMI.
I would be happy if you could share your code with me (ekrem03@gmail.com)
Hi Emre!
ReplyDeleteThank you for sharing your idea.
I'm trying to establish Ethernet connection for TI f28m36. And I have some problems with DMA functions of example project.
Could you mail me the whole code?
oleg.karnienko@gmail.com
Thanks in advance!
Hi,
ReplyDeleteCould you please email me the source code.
my email : gsmsby@yahoo.com
Thank you
Novita A
Hi,
ReplyDeleteCould you please email me the source code.
my email : luongtien.bkan@gmail.com
thank you!
Could you please send me as well the source code.
ReplyDeleteMy email is: didogm@gmail.com
Thank you in advance.
Cheers!