| View previous topic :: View next topic |
| Author |
Message |
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
Posted: Fri Oct 27, 2006 3:22 pm Post subject: The secrets of mikroC ENC28J60 library |
|
|
Hello,
If you want to know how to send an ethernet packet with mikroC library, calculate a checksum using the ENC28J60 hardware, and many other low level secret functions, have a look at this :
http://www.micro-examples.com/public/microex-navig/doc/090-enc28j60-library.html
It does fit to mikroBasic and mikroPascal too.
Comments & questions are welcome ! _________________ BrunoG, Administrator |
|
| Back to top |
|
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
|
| Back to top |
|
dobova86
Joined: 04 Oct 2006 Posts: 1
|
Posted: Fri Nov 17, 2006 9:40 pm Post subject: |
|
|
hi Bruno,
Thanks very much...I need it !!
Ciao
Dome |
|
| Back to top |
|
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
Posted: Sun Nov 19, 2006 6:28 pm Post subject: |
|
|
Hi Dome, nice to see you here
happy coding ! _________________ BrunoG, Administrator |
|
| Back to top |
|
joern2k2
Joined: 05 Jun 2007 Posts: 2
|
Posted: Tue Jun 05, 2007 8:19 am Post subject: Examples for MicroC |
|
|
Hey,
I tried to use the secret funtions because I have had the same problems that my Code is more than ~1,5kbytes. I would like to build an embedded webserver on the dsPic30F6014A, but it doesn't work when the code is to big. I don't know where to use the SPI_Ethernet_txpacket() function und how to split my source code into parts smaller than ~1,5kbytes. I need an example for TCP, an that isn't given from BrunoG. Does anybody can give me an example for the MicroC Compiler? Thank you very much.
Greetings, Joern |
|
| Back to top |
|
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
Posted: Tue Jun 05, 2007 5:45 pm Post subject: |
|
|
Hi joern2k2,
can you please be more specific, I don't understant if 1.5 Kbytes is your code size or packet size ?
what do you mean by "it doesn't work when the code is to big" ?
Thanks, _________________ BrunoG, Administrator |
|
| Back to top |
|
joern2k2
Joined: 05 Jun 2007 Posts: 2
|
Posted: Wed Jun 06, 2007 7:21 am Post subject: |
|
|
Hey BrunoG,
Thanks for your answer!
Problem:
I want to implement an embedded Webserver on the microcontroller dsPIC30F6014A. Therefore I have a code with inline html code with a code size bigger than 1,5kbyte.
What I have:
I have a Code with a codesize of ~1,5kbyte and used the functions from Mikroelektronika but with this functions I can only make one paket with a size of ~ 1,5kbyte.
When the paketsize is smaller than ~1,5kbyte the PC displays the website.
When the paketsize is bigger than 1.5kbyte the paket gets lost from the way from microcontroller to the pc an then the internet explorer does not display the website anymore. I figured it out with ethereal.
Waht I need:
What I need is a code size more than 1,5kbyte. In the forum of Mikroelektronika was written, that is is not possible to transmit packets bigger than ~ 1,5kbyte and so I have to split the code in 2 packets each smaller than 1,5kbyte. Therefore I wanted to use your described "secret functions". Your example works very well, but what I need is not the UDP transmission. I need the TCP transmission because I want to implement the embedded webserver on the microcontroller. Therefore I have to transmit a code with a size bigger than 1,5kbyte with inline html code.
Do you have any example with the "secret functions" for TCP transmission? |
|
| Back to top |
|
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
Posted: Wed Jun 06, 2007 9:42 am Post subject: |
|
|
Ok joern2k2,
Due to its very small ROM footprint, the serial ethernet library is not designed to handle TCP/IP fragmented packets : the reply to an http GET request can't exceed the limit you mention.
The workaround is to include other requests to the HTML page (frames, iframes, javascript...) to extend its content.
This way, the embedded serveur can serve a volume content that far exceeds the packet size limit.
But for a single object (any type it is : html page, image, CSS, javascript) you will always have this 1.5K limit.
Besides, a full TCP/IP stack could be written with the available built-in functions, but until now I had no need to do that.
In the future maybe...  _________________ BrunoG, Administrator |
|
| Back to top |
|
mbluethunder7000
Joined: 24 May 2008 Posts: 7 Location: Egypt
|
Posted: Mon May 26, 2008 8:33 pm Post subject: |
|
|
Hi BrunoG
First, I would like to illustrate the main subject of my issue. I am preparing a project using dsPIC33F; I bought the board from mikroelektronika and bought some other extra boards including the ENC28J60.
I need to send data between my laptop and the dsPIC33F board using Ethernet communication cross over link.
I spent around three weeks to read and understand the operation of the Ethernet module ENC28J60, dsPIC33F and some protocols like TCP/IP.
The main problem I have, that i don't know where is the correct beginning to send data between ENC28J60 and dsPIC33F in correct way.
Also, I didn't found any complete project on the internet to take it as a guide for me.
I am using the MikroC complier and the data which I need to transmit is values (Numbers Only).
Last week I found your page and your example using UDP port. I tried your code with some modifications based on dsPIC
Kindly find the code after modifications
| Quote: |
/*
* file : ethdemo.c
* project : ENC28J60 SPI ETHERNET LIBRARY DEMO
* author : Bruno Gavand
* compiler : mikroC V6.2
* date : october 27, 2006
*
* description :
* This program shows how to use undocumented mikroC Spi Ethernet functions
* This example is an UDP push server :
*
* Start Ethernet services with ARP and PING reply
* Listen to the UDP port 33000 for an incoming request :
* 'b' will start the push
* 'e' will stop the stop
* any other incoming char has no effect
* If push is enabled :
* send to the remote UDP host a string with PORTB value one time per second
*
* target device :
* Tested with PIC18F452 and PIC18F4620 @ 32 Mhz (8 Mhz crystal + HS PLL)
*
* Licence :
* Feel free to use this source code at your own risks.
*
* history :
october 30, 2006 : ARP cache management, little bug fixed. Thanks Philippe !
*
* see more details on http://www.micro-examples.com/
*/
#define NULL 0
#define Spi_Ethernet_FULLDUPLEX 1
#define TRANSMIT_START 0x19AE
#define REPLY_START (TRANSMIT_START + 1) // reply buffer starts after per packet control byte
// some ENC28J60 registers, see datasheet
#define ERDPTL 0x00
#define ERDPTH 0x01
#define ECON1 0x1f
#define EDMACSL 0x16
#define EDMACSH 0x17
/***********************************
* RAM variables
*/
unsigned char macAddr[6] = {0x00, 0x1B, 0x24, 0xC8, 0xAF, 0xE7} ; // my MAC address
unsigned char ipAddr[4] = {192, 168, 1, 101} ; // my IP address
unsigned char destIpAddr[4] ; // IP address
unsigned char transmit = 0 ;
unsigned char tmr = 0 ;
unsigned long longTmr = 0 ;
unsigned int destPortNum = 0 ;
char udpStr[16] = "PORTB=" ;
#define ARPCACHELEN 3
struct
{
unsigned char valid ;
unsigned long tmr ;
unsigned char ip[4] ;
unsigned char mac[6] ;
} arpCache[ARPCACHELEN] ;
/*******************************************
* functions
*/
/*
* ARP resolution
* this function returns the MAC address of an IP address
* an ARP cache is used
*/
unsigned char *arpResolv(unsigned char *ip)
{
unsigned char i ; // general purpose register
unsigned int rdptr ; // backup of ENC read pointer register
unsigned char freeSlot ; // index of free slot in ARP cache
unsigned long tmrSlot ; // oldest slot timer in ARP cache
tmrSlot = 0xffffffff ; // will try to find less than this !
// step in ARP cache
for(i = 0 ; i < ARPCACHELEN; i++)
{
// oldest slots must expire
if(arpCache[i].tmr < longTmr - 1000) // too old ?
{
arpCache[i].tmr = 0 ; // clear timer
arpCache[i].valid = 0 ; // disable slot
}
// is it the address I want in a valid slot ?
if(arpCache[i].valid && (memcmp(arpCache[i].ip, ip, 4) == 0))
{
return(arpCache[i].mac) ; // yes, return ready to use MAC addr
}
// find older slot, will be needed further
if(arpCache[i].tmr < tmrSlot)
{
tmrSlot = arpCache[i].tmr ; // save best timer
freeSlot = i ; // save best index
}
}
// select ENC register bank 0
Spi_Ethernet_clearBitReg(ECON1, 0b00000001) ;
Spi_Ethernet_clearBitReg(ECON1, 0b00000010) ;
/***************************
* first, build eth header
*/
Spi_Ethernet_memcpy(REPLY_START, "\xff\xff\xff\xff\xff\xff", 6) ; // destination is broadcast
Spi_Ethernet_memcpy(REPLY_START + 6, macAddr, 6) ; // source : my mac addr
Spi_Ethernet_writeMemory(REPLY_START + 12, 8, 6, 1) ; // protocol is ARP
/****************************
* second, build ARP packet
*/
/*
* 0, 1 : hardware type = ethernet
* 8, 0 : protocole type = ip
* 6, 4 : HW size = 6, protocol size = 4
* 0, 1 : ARP opcode = request
*/
Spi_Ethernet_memcpy(REPLY_START + 14, "\x0\x01\x08\x00\x06\x04\x00\x01", ;
Spi_Ethernet_memcpy(REPLY_START + 22, macAddr, 6) ; // mac addr source
Spi_Ethernet_memcpy(REPLY_START + 28, ipAddr, 4) ; // ip addr source
Spi_Ethernet_memcpy(REPLY_START + 32, "\0\0\0\0\0\0", 6) ; // mac addr destination : broadcast addr
Spi_Ethernet_memcpy(REPLY_START + 38, ip, 4) ; // who has this ip addr ?
/*******************************************************************
* third, send packet over wires, ARP request packet is 42 bytes len
*/
Spi_Ethernet_txPacket(42) ;
tmr = 0 ;
while(tmr < 45) // allows around 3 seconds for reply
{
Spi_Ethernet_doPacket() ; // do not stop eth services !
// select ENC register bank 0, may have been changed by library
Spi_Ethernet_clearBitReg(ECON1, 0b00000001) ;
Spi_Ethernet_clearBitReg(ECON1, 0b00000010) ;
/*
* ERDPT[H|L] registers are used by library :
* always save them before doing anything else !
*/
rdptr = (Spi_Ethernet_readReg(ERDPTH) << + Spi_Ethernet_readReg(ERDPTL) ;
/*
* check if packet is ARP reply to my request (last byte = 2 means ARP reply)
*/
if((Spi_Ethernet_memcmp(REPLY_START + 12, "\x08\x06\x00\x01\x08\x00\x06\x04\x00\x02", 10) == 0)
&& (Spi_Ethernet_memcmp(REPLY_START, macAddr, 6) == 0) // is it my MAC addr ?
&& (Spi_Ethernet_memcmp(REPLY_START + 28, ip, 4) == 0) // is it my IP addr ?
)
{
/*
* save remote MAC addr in a free slot of the cache
*/
// copy MAC addr
arpCache[freeSlot].mac[0] = Spi_Ethernet_readMem(REPLY_START + 22) ;
arpCache[freeSlot].mac[1] = Spi_Ethernet_readMem(REPLY_START + 23) ;
arpCache[freeSlot].mac[2] = Spi_Ethernet_readMem(REPLY_START + 24) ;
arpCache[freeSlot].mac[3] = Spi_Ethernet_readMem(REPLY_START + 25) ;
arpCache[freeSlot].mac[4] = Spi_Ethernet_readMem(REPLY_START + 26) ;
arpCache[freeSlot].mac[5] = Spi_Ethernet_readMem(REPLY_START + 27) ;
// copy IP addr
memcpy(arpCache[freeSlot].ip, ip, 4) ;
// enable slot
arpCache[freeSlot].valid = 1 ;
// timestamp
arpCache[freeSlot].tmr = longTmr ;
// restore ERDPT before exiting
Spi_Ethernet_writeAddr(ERDPTL, rdptr) ;
// return the MAC addr pointer
return(arpCache[freeSlot].mac) ;
}
// restore ERDPT before doing a new call to the library
Spi_Ethernet_writeAddr(ERDPTL, rdptr) ;
}
// failed, no response : MAC addr is null
return((unsigned char *)NULL) ;
}
/*
* send an UDP packet :
* destIp : remote host IP address
* sourcePort : local UDP source port number
* destPort : destination UDP port number
* pkt : pointer to packet to transmit
* pktLen : length in bytes of packet to transmit
*/
void sendUDP(unsigned char *destIP, unsigned int sourcePort, unsigned int destPort, unsigned char *pkt, unsigned int pktLen)
{
unsigned char *destMac ; // destination MAC addr
static int idUniq ; // uniq packet id (serial number)
unsigned char align ; // alignement flag
unsigned int totlen ; // total packet length
unsigned int rdptr ; // ENC read pointer backup
// is destination port valid ?
if(destPort == 0)
{
return ; // no, do nothing
}
// does destination IP address exist ?
if((destMac = arpResolv(destIP)) == NULL)
{
return ; // no MAC addr matches, do nothing
}
// select ENC register bank 0
Spi_Ethernet_clearBitReg(ECON1, 0b00000001) ;
Spi_Ethernet_clearBitReg(ECON1, 0b00000010) ;
/*
* ERDPT[H|L] registers are used by library :
* always save them before doing anything else !
*/
rdptr = (Spi_Ethernet_readReg(ERDPTH) << + Spi_Ethernet_readReg(ERDPTL) ;
/**************************
* first, build eth header
*/
Spi_Ethernet_memcpy(REPLY_START, destMAC, 6) ; // destination
Spi_Ethernet_memcpy(REPLY_START + 6, macAddr, 6) ; // source
Spi_Ethernet_writeMemory(REPLY_START + 12, 8, 0, 1) ; // IP type
/**************************
* second, build IP header
*/
totlen = 20 + 8 + pktLen ;
Spi_Ethernet_writeMemory(REPLY_START + 14, 0x45, 0, 1) ; // IPV4, IHL = 20 bytes, TOS = 0
Spi_Ethernet_writeMemory(REPLY_START + 16, totlen >> 8, totlen, 1) ; // total packet length
Spi_Ethernet_memcpy(REPLY_START + 18, (char *)&(idUniq++), 2) ; // identification
Spi_Ethernet_writeMemory(REPLY_START + 20, 0, 0, 1) ; // flags + 0, fragment offset = 0, TTL = 128, protocol = UDP
Spi_Ethernet_writeMemory(REPLY_START + 22, 0x80, 0x11, 1) ; // flags + 0, fragment offset = 0, TTL = 128, protocol = UDP
Spi_Ethernet_writeMemory(REPLY_START + 24, 0, 0, 1) ; // clear IP checksum
Spi_Ethernet_memcpy(REPLY_START + 26, ipAddr, 4) ; // source
Spi_Ethernet_memcpy(REPLY_START + 30, destIP, 4) ; // destination
/***************************
* third, build UDP header
*/
totlen = pktLen + 8 ;
Spi_Ethernet_writeMemory(REPLY_START + 34, sourcePort >> 8, sourcePort, 1) ; // source port
Spi_Ethernet_writeMemory(REPLY_START + 36, destPort >> 8, destPort, 1) ; // destination port
Spi_Ethernet_writeMemory(REPLY_START + 38, totlen >> 8, totlen, 1) ; // packet length
Spi_Ethernet_writeMemory(REPLY_START + 40, 0, 0, 1) ; // clear UDP checksum
Spi_Ethernet_memcpy(REPLY_START + 42, pkt, pktLen) ; // payload
/*****************
* fourth, IP checksum
*/
Spi_Ethernet_checksum(REPLY_START + 14, 20) ;
Spi_Ethernet_writeMemory(REPLY_START + 24, Spi_Ethernet_readReg(EDMACSH), Spi_Ethernet_readReg(EDMACSL), 1) ;
/*****************
* fifth, UDP checksum
*/
// pseudo header
// word alignement
align = totlen & 1 ;
Spi_Ethernet_writeMemory(REPLY_START + 42 + pktLen, 0, 0, 0) ; // clear
// build pseudo header
Spi_Ethernet_RAMcopy(REPLY_START + 26, REPLY_START + 26 + 8, REPLY_START + 42 + pktLen + align, 0) ;
Spi_Ethernet_writeMemory(REPLY_START + 42 + pktLen + align + 8, 0, 17, 1) ;
Spi_Ethernet_putByte(totlen >> ;
Spi_Ethernet_putByte(totlen) ;
// ready for checksum
Spi_Ethernet_checksum(REPLY_START + 34, totlen + 12 + align) ;
Spi_Ethernet_writeMemory(REPLY_START + 40, Spi_Ethernet_readReg(EDMACSH), Spi_Ethernet_readReg(EDMACSL), 1) ;
/**************************
* sixth, send packet over wires
*/
Spi_Ethernet_txPacket(42 + pktLen) ;
// restore ERDPT registers before exiting
Spi_Ethernet_writeAddr(ERDPTL, rdptr) ;
}
/*
* no TCP
*/
unsigned int Spi_Ethernet_userTCP(unsigned char *remoteHost, unsigned int remotePort, unsigned int localPort, unsigned int reqLength)
{
return(0) ;
}
/*
* save remote UDP host and port number, then reply with 'Start'
*/
unsigned int Spi_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort, unsigned int destPort, unsigned int reqLength)
{
if(destPort != 33000) return(0) ; // service is on port 33000
switch(Spi_Ethernet_getByte())
{
// begin command
case 'b':
case 'B':
transmit = 1 ; // set transmission flag
memcpy(destIPAddr, remoteHost, 4) ; // save remote host IP addr
destPortNum = remotePort ; // save remote host port number
Spi_Ethernet_putByte('B') ; // reply with 'Begin' string
Spi_Ethernet_putByte('e') ;
Spi_Ethernet_putByte('g') ;
Spi_Ethernet_putByte('i') ;
Spi_Ethernet_putByte('n') ;
return(5) ; // 5 bytes to transmit
// end command
case 'e':
case 'E':
transmit = 0 ; // clear transmission flag
Spi_Ethernet_putByte('E') ; // reply with 'End'
Spi_Ethernet_putByte('n') ;
Spi_Ethernet_putByte('d') ;
return(3) ; // 3 bytes to transmit
// error
default:
Spi_Ethernet_putByte('?') ;
return(1) ;
}
}
/*
* timers tmr and longTmr are incremented Fosc / 4 / 65536 / TMR1prescaler
* TMR1prescaler is 8 (see main)
* about 15.25 times per second with 32 Mhz clock
*/
void interrupt()
{
if (IFS0bits.T1IF) // timer1 overflow ?
{
tmr++ ; // increment timers
longTmr++ ;
IFS0bits.T1IF = 0 ; // clear timer1 overflow flag
}
}
/*
* main entry
*/
unsigned adcRes;
void main()
{
AD1PCFGL=0XFFFF;
AD1PCFGH=0XFFFF;
TRISBbits.TRISB1 = 1;
adcRes = Adc1_Read(1, ADC_12bit);
PORTB = 0 ;
TRISB = 0xff ; // set PORTB as input
PORTF = 0 ;
TRISF = 0x8010 ; // set PORTC as input except for bits 0 (RESET) and 1 (CS)
T1CON = 0x8010 ; // 16 bits, from other source, prescaler 1:8, oscillator disabled, not synchronized, internal clock, enabled
IFS0bits.T1IF = 0 ; // clear TMR1 overflow interrupt flag
IEC0bits.T1IE = 1 ; // enable interrupt on TMR1 overflow
// init ARP cache
memset(&arpCache, 0, sizeof(arpCache)) ;
/*
* starts Spi_Ethernet with :
* reset bit on RF0,
* CS bit on RF1,
* my MAC & IP address,
* full duplex
*/
Spi_Init() ;
Spi_Ethernet_Init(&PORTF, 0, &PORTF, 1, macAddr, ipAddr, Spi_Ethernet_FULLDUPLEX) ;
while(1) // do forever
{
Spi_Ethernet_doPacket() ; // process incoming Ethernet packets
if(transmit && (tmr > 15)) // transmit one UDP packet per second
{
ByteToStr(PORTB, udpStr + 6) ; // read PORTB value and convert to string
sendUDP(destIpAddr, 3456, destPortNum, udpStr, sizeof(udpStr)) ; // send to remote host
tmr = 0 ; // reset timer
}
}
}
|
After building the HEX file and upload it on dsPIC, my laptop couldn’t find the ENC and I couldn’t make a PING.
I don’t know where the wrong is but I need to finalize this issue. I think that there are some configuration should be done on laptop or some variables have to be changed in the code.
I hope you could help me to figure the problem here
I am Sorry if my English is not good enough to express the meaning very well. |
|
| Back to top |
|
mbluethunder7000
Joined: 24 May 2008 Posts: 7 Location: Egypt
|
Posted: Wed May 28, 2008 5:53 am Post subject: |
|
|
| Could you please advise urgently? |
|
| Back to top |
|
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
Posted: Wed May 28, 2008 5:18 pm Post subject: |
|
|
Well, my ENC28J60 ethernet web page is about mikroC for PIC V6.2, and you are talking about mikroC for dsPIC V4.0 : it is not sure at all the same tips & tricks will work, I did not test, but it could.
I suggest you to try step by step : first just use the basic example of the manual with the Spi_Ethernet_doPacket() call in the main loop, it will help you to know if your hardware is correct or not using the PING test.
When the PIG responds correctly, then add the other functions one by one. _________________ BrunoG, Administrator |
|
| Back to top |
|
mbluethunder7000
Joined: 24 May 2008 Posts: 7 Location: Egypt
|
Posted: Fri Jun 06, 2008 11:51 pm Post subject: |
|
|
| BrunoG wrote: | Well, my ENC28J60 ethernet web page is about mikroC for PIC V6.2, and you are talking about mikroC for dsPIC V4.0 : it is not sure at all the same tips & tricks will work, I did not test, but it could.
I suggest you to try step by step : first just use the basic example of the manual with the Spi_Ethernet_doPacket() call in the main loop, it will help you to know if your hardware is correct or not using the PING test.
When the PIG responds correctly, then add the other functions one by one. |
Hi again
Few days ago, I tried to use your code of the ENC with dsPIC33f.
First, I would like to say that I discovered that the pin arrangement of the dsPIC33 for ENC is different from the standard board and I arranged it based on the real state. It works now on PortG not PortF
Now, I adjust your code and modify some lines. I am able to ping with the ENC. I opened the UDP terminal from MikroC and I connected to the board then send (b) to begin but after that I have no any activates on the port
I am using pin 1 in port b as an analogue input and use the built-in potentiometers on the board to simulate the analogue signals. I display this value on the LCD to compare it with the value which will appear on the UDP terminal
No the only thing I couldn’t do it is how I can send the analogue value to the udp terminal.
Plus I discovered that I have to make ping every time I use the ENC board and I need some automatic detection for it.
I hope you can help me in this issue.
This is the my code
| Quote: |
#define NULL 0
#define SPI_Ethernet_HALFDUPLEX 0
#define SPI_Ethernet_FULLDUPLEX 1
#define TRANSMIT_START 0x19AE
#define REPLY_START (TRANSMIT_START + 1) // reply buffer starts after per packet control byte
// some ENC28J60 registers, see datasheet
#define ERDPTL 0x00
#define ERDPTH 0x01
#define ECON1 0x1f
#define EDMACSL 0x16
#define EDMACSH 0x17
/***********************************
* RAM variables
*/
unsigned char macAddr[6] = {0x00, 0x14, 0xA5, 0x76, 0x19, 0x3f} ; // set MAC address
unsigned char ipAddr[4] = {192, 168, 20, 60} ; // set IP address
unsigned char destIpAddr[4] ; // IP address
unsigned char transmit = 0 ;
unsigned char tmr = 0 ;
unsigned long longTmr = 0 ;
unsigned int destPortNum = 0 ;
unsigned adcRes;
char udpStr[21] = "PORTB=" ;
char text[16];
#define ARPCACHELEN 3
struct
{
unsigned char valid ;
unsigned long tmr ;
unsigned char ip[4] ;
unsigned char mac[6] ;
}
arpCache[ARPCACHELEN] ;
//--- Master/Slave mode, SPI2CON1<5>
unsigned _SPI_MASTER = 0x0020; // Master mode
unsigned _SPI_SLAVE = 0x0000; // Slave mode
//--- data length select, SPI2CON1<10>
unsigned _SPI_16_BIT = 0x0400; // 16-bit mode
unsigned _SPI_8_BIT = 0x0000; // 8-bit mode
//--- secondary prescale (Master mode), SPI2CON1<4:2>
unsigned _SPI_PRESCALE_SEC_1 = 0x001C; // secondary prescale 1:1
unsigned _SPI_PRESCALE_SEC_2 = 0x0018; // secondary prescale 2:1
unsigned _SPI_PRESCALE_SEC_3 = 0x0014; // secondary prescale 3:1
unsigned _SPI_PRESCALE_SEC_4 = 0x0010; // secondary prescale 4:1
unsigned _SPI_PRESCALE_SEC_5 = 0x000C; // secondary prescale 5:1
unsigned _SPI_PRESCALE_SEC_6 = 0x0008; // secondary prescale 6:1
unsigned _SPI_PRESCALE_SEC_7 = 0x0004; // secondary prescale 7:1
unsigned _SPI_PRESCALE_SEC_8 = 0x0000; // secondary prescale 8:1
//--- primary prescale (Master mode), SPI2CON1<1:0>
unsigned _SPI_PRESCALE_PRI_1 = 0x0003; // primary prescale 1:1
unsigned _SPI_PRESCALE_PRI_4 = 0x0002; // primary prescale 4:1
unsigned _SPI_PRESCALE_PRI_16 = 0x0001; // primary prescale 16:1
unsigned _SPI_PRESCALE_PRI_64 = 0x0000; // primary prescale 64:1
//--- Slave select enable bit (Slave Mode), SPI2CON1<7>
unsigned _SPI_SS_ENABLE = 0x0080; // SS used for the Slave mode
unsigned _SPI_SS_DISABLE = 0x0000; // SS not used for the Slave mode
//--- SPI data input sample phase, SPI2CON1<9>
unsigned _SPI_DATA_SAMPLE_MIDDLE = 0x0000; // data sampled in the middle of data output time
unsigned _SPI_DATA_SAMPLE_END = 0x2000; // data sampled at end of data output time
//--- Clock Polarity Select bit, SPI2CON1<6>
unsigned _SPI_CLK_IDLE_LOW = 0x0000; // IDLE state is Lo, ACTIVE state is Hi
unsigned _SPI_CLK_IDLE_HIGH = 0x0040; // IDLE state is Hi, ACTIVE state is Lo
//--- Clock EDGE select bit (where output data is valid), SPI2CON1<8>
unsigned _SPI_ACTIVE_2_IDLE = 0x0000; // data is valid on ACTIVE-to-IDLE transition
// (data changes on IDLE-to-ACTIVE transition)
unsigned _SPI_IDLE_2_ACTIVE = 0x0100; // data is valid on IDLE-to-ACTIVE transition
// (data changes on ACTIVE-to-IDLE transition)
/*******************************************
* functions
*/
/*
* ARP resolution
* this function returns the MAC address of an IP address
* an ARP cache is used
*/
unsigned char *arpResolv(unsigned char *ip)
{
unsigned char i ; // general purpose register
unsigned int rdptr ; // backup of ENC read pointer register
unsigned char freeSlot ; // index of free slot in ARP cache
unsigned long tmrSlot ; // oldest slot timer in ARP cache
tmrSlot = 0xffffffff ; // will try to find less than this !
// step in ARP cache
for(i = 0 ; i < ARPCACHELEN; i++)
{
// oldest slots must expire
if(arpCache[i].tmr < longTmr - 1000) // too old ?
{
arpCache[i].tmr = 0 ; // clear timer
arpCache[i].valid = 0 ; // disable slot
}
// is it the address I want in a valid slot ?
if(arpCache[i].valid && (memcmp(arpCache[i].ip, ip, 4) == 0))
{
return(arpCache[i].mac) ; // yes, return ready to use MAC addr
}
// find older slot, will be needed further
if(arpCache[i].tmr < tmrSlot)
{
tmrSlot = arpCache[i].tmr ; // save best timer
freeSlot = i ; // save best index
}
}
// select ENC register bank 0
Spi_Ethernet_clearBitReg(ECON1, 0b00000001) ;
Spi_Ethernet_clearBitReg(ECON1, 0b00000010) ;
/***************************
* first, build eth header
*/
Spi_Ethernet_memcpy(REPLY_START, "\xff\xff\xff\xff\xff\xff", 6) ; // destination is broadcast
Spi_Ethernet_memcpy(REPLY_START + 6, macAddr, 6) ; // source : my mac addr
Spi_Ethernet_writeMemory(REPLY_START + 12, 8, 6, 1) ; // protocol is ARP
/****************************
* second, build ARP packet
*/
/*
* 0, 1 : hardware type = ethernet
* 8, 0 : protocole type = ip
* 6, 4 : HW size = 6, protocol size = 4
* 0, 1 : ARP opcode = request
*/
Spi_Ethernet_memcpy(REPLY_START + 14, "\x0\x01\x08\x00\x06\x04\x00\x01", ;
Spi_Ethernet_memcpy(REPLY_START + 22, macAddr, 6) ; // mac addr source
Spi_Ethernet_memcpy(REPLY_START + 28, ipAddr, 4) ; // ip addr source
Spi_Ethernet_memcpy(REPLY_START + 32, "\0\0\0\0\0\0", 6) ; // mac addr destination : broadcast addr
Spi_Ethernet_memcpy(REPLY_START + 38, ip, 4) ; // who has this ip addr ?
/*******************************************************************
* third, send packet over wires, ARP request packet is 42 bytes len
*/
Spi_Ethernet_txPacket(42) ;
tmr = 0 ;
while(tmr < 45) // allows around 3 seconds for reply
{
Spi_Ethernet_doPacket() ; // do not stop eth services !
// select ENC register bank 0, may have been changed by library
Spi_Ethernet_clearBitReg(ECON1, 0b00000001) ;
Spi_Ethernet_clearBitReg(ECON1, 0b00000010) ;
/*
* ERDPT[H|L] registers are used by library :
* always save them before doing anything else !
*/
rdptr = (Spi_Ethernet_readReg(ERDPTH) << + Spi_Ethernet_readReg(ERDPTL) ;
/*
* check if packet is ARP reply to my request (last byte = 2 means ARP reply)
*/
if((Spi_Ethernet_memcmp(REPLY_START + 12, "\x08\x06\x00\x01\x08\x00\x06\x04\x00\x02", 10) == 0)
&& (Spi_Ethernet_memcmp(REPLY_START, macAddr, 6) == 0) // is it my MAC addr ?
&& (Spi_Ethernet_memcmp(REPLY_START + 28, ip, 4) == 0) // is it my IP addr ?
)
{
/*
* save remote MAC addr in a free slot of the cache
*/
// copy MAC addr
arpCache[freeSlot].mac[0] = Spi_Ethernet_readMem(REPLY_START + 22) ;
arpCache[freeSlot].mac[1] = Spi_Ethernet_readMem(REPLY_START + 23) ;
arpCache[freeSlot].mac[2] = Spi_Ethernet_readMem(REPLY_START + 24) ;
arpCache[freeSlot].mac[3] = Spi_Ethernet_readMem(REPLY_START + 25) ;
arpCache[freeSlot].mac[4] = Spi_Ethernet_readMem(REPLY_START + 26) ;
arpCache[freeSlot].mac[5] = Spi_Ethernet_readMem(REPLY_START + 27) ;
// copy IP addr
memcpy(arpCache[freeSlot].ip, ip, 4) ;
// enable slot
arpCache[freeSlot].valid = 1 ;
// timestamp
arpCache[freeSlot].tmr = longTmr ;
// restore ERDPT before exiting
Spi_Ethernet_writeAddr(ERDPTL, rdptr) ;
// return the MAC addr pointer
return(arpCache[freeSlot].mac) ;
}
// restore ERDPT before doing a new call to the library
Spi_Ethernet_writeAddr(ERDPTL, rdptr) ;
}
// failed, no response : MAC addr is null
return((unsigned char *)NULL) ;
}
/*
* send an UDP packet :
* destIp : remote host IP address
* sourcePort : local UDP source port number
* destPort : destination UDP port number
* pkt : pointer to packet to transmit
* pktLen : length in bytes of packet to transmit
*/
void sendUDP(unsigned char *destIP, unsigned int sourcePort, unsigned int destPort, unsigned char *pkt, unsigned int pktLen)
{
unsigned char *destMac ; // destination MAC addr
static int idUniq ; // uniq packet id (serial number)
unsigned char align ; // alignement flag
unsigned int totlen ; // total packet length
unsigned int rdptr ; // ENC read pointer backup
// is destination port valid ?
if(destPort == 0)
{
return ; // no, do nothing
}
// does destination IP address exist ?
if((destMac = arpResolv(destIP)) == NULL)
{
return ; // no MAC addr matches, do nothing
}
// select ENC register bank 0
Spi_Ethernet_clearBitReg(ECON1, 0b00000001) ;
Spi_Ethernet_clearBitReg(ECON1, 0b00000010) ;
/*
* ERDPT[H|L] registers are used by library :
* always save them before doing anything else !
*/
rdptr = (Spi_Ethernet_readReg(ERDPTH) << + Spi_Ethernet_readReg(ERDPTL) ;
/**************************
* first, build eth header
*/
Spi_Ethernet_memcpy(REPLY_START, destMAC, 6) ; // destination
Spi_Ethernet_memcpy(REPLY_START + 6, macAddr, 6) ; // source
Spi_Ethernet_writeMemory(REPLY_START + 12, 8, 0, 1) ; // IP type
/**************************
* second, build IP header
*/
totlen = 20 + 8 + pktLen ;
Spi_Ethernet_writeMemory(REPLY_START + 14, 0x45, 0, 1) ; // IPV4, IHL = 20 bytes, TOS = 0
Spi_Ethernet_writeMemory(REPLY_START + 16, totlen >> 8, totlen, 1) ; // total packet length
Spi_Ethernet_memcpy(REPLY_START + 18, (char *)&(idUniq++), 2) ; // identification
Spi_Ethernet_writeMemory(REPLY_START + 20, 0, 0, 1) ; // flags + 0, fragment offset = 0, TTL = 128, protocol = UDP
Spi_Ethernet_writeMemory(REPLY_START + 22, 0x80, 0x11, 1) ; // flags + 0, fragment offset = 0, TTL = 128, protocol = UDP
Spi_Ethernet_writeMemory(REPLY_START + 24, 0, 0, 1) ; // clear IP checksum
Spi_Ethernet_memcpy(REPLY_START + 26, ipAddr, 4) ; // source
Spi_Ethernet_memcpy(REPLY_START + 30, destIP, 4) ; // destination
/***************************
* third, build UDP header
*/
totlen = pktLen + 8 ;
Spi_Ethernet_writeMemory(REPLY_START + 34, sourcePort >> 8, sourcePort, 1) ; // source port
Spi_Ethernet_writeMemory(REPLY_START + 36, destPort >> 8, destPort, 1) ; // destination port
Spi_Ethernet_writeMemory(REPLY_START + 38, totlen >> 8, totlen, 1) ; // packet length
Spi_Ethernet_writeMemory(REPLY_START + 40, 0, 0, 1) ; // clear UDP checksum
Spi_Ethernet_memcpy(REPLY_START + 42, pkt, pktLen) ; // payload
/*****************
* fourth, IP checksum
*/
Spi_Ethernet_checksum(REPLY_START + 14, 20) ;
Spi_Ethernet_writeMemory(REPLY_START + 24, Spi_Ethernet_readReg(EDMACSH), Spi_Ethernet_readReg(EDMACSL), 1) ;
/*****************
* fifth, UDP checksum
*/
// pseudo header
// word alignement
align = totlen & 1 ;
Spi_Ethernet_writeMemory(REPLY_START + 42 + pktLen, 0, 0, 0) ; // clear
// build pseudo header
Spi_Ethernet_RAMcopy(REPLY_START + 26, REPLY_START + 26 + 8, REPLY_START + 42 + pktLen + align, 0) ;
Spi_Ethernet_writeMemory(REPLY_START + 42 + pktLen + align + 8, 0, 17, 1) ;
Spi_Ethernet_putByte(totlen >> ;
Spi_Ethernet_putByte(totlen) ;
// ready for checksum
Spi_Ethernet_checksum(REPLY_START + 34, totlen + 12 + align) ;
Spi_Ethernet_writeMemory(REPLY_START + 40, Spi_Ethernet_readReg(EDMACSH), Spi_Ethernet_readReg(EDMACSL), 1) ;
/**************************
* sixth, send packet over wires
*/
Spi_Ethernet_txPacket(42 + pktLen) ;
// restore ERDPT registers before exiting
Spi_Ethernet_writeAddr(ERDPTL, rdptr) ;
}
/*
* no TCP
*/
unsigned int Spi_Ethernet_userTCP(unsigned char *remoteHost, unsigned int remotePort, unsigned int localPort, unsigned int reqLength)
{
return(0) ;
}
/*
* save remote UDP host and port number, then reply with 'Start'
*/
unsigned int Spi_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort, unsigned int destPort, unsigned int reqLength)
{
if(destPort != 33000) return(0) ; // service is on port 33000
switch(Spi_Ethernet_getByte())
{
// begin command
case 'b':
case 'B':
transmit = 1 ; // set transmission flag
memcpy(destIpAddr, remoteHost, 4) ; // save remote host IP addr
destPortNum = remotePort ; // save remote host port number
Spi_Ethernet_putByte('B') ; // reply with 'Begin' string
Spi_Ethernet_putByte('e') ;
Spi_Ethernet_putByte('g') ;
Spi_Ethernet_putByte('i') ;
Spi_Ethernet_putByte('n') ;
return(5) ; // 5 bytes to transmit
// end command
case 'e':
case 'E':
transmit = 0 ; // clear transmission flag
Spi_Ethernet_putByte('E') ; // reply with 'End'
Spi_Ethernet_putByte('n') ;
Spi_Ethernet_putByte('d') ;
return(3) ; // 3 bytes to transmit
// error
default:
Spi_Ethernet_putByte('?') ;
return(1) ;
}
}
/*
* timers tmr and longTmr are incremented Fosc / 4 / 65536 / TMR1prescaler
* TMR1prescaler is 8 (see main)
* about 15.25 times per second with 32 Mhz clock
*/
void interrupt()
{
if (IFS0bits.T1IF) // timer1 overflow ?
{
tmr++ ; // increment timers
longTmr++ ;
IFS0bits.T1IF = 0 ; // clear timer1 overflow flag
}
}
/************************************************************
* main entry
*/
void main()
{
AD1PCFGL=0X0000; // all pins are analogue
AD1PCFGH=0X0000; // all pins are analogue
PORTD=0X0000;
TRISD=0X0000;
PORTB = 0X0000 ;
TRISB = 0xFFFF ; // set PORTB as input
PORTG = 0X0000 ;
TRISG = 0xCFFF ; // set PORTG as input except for bits 13 (RESET) and 12 (CS)
IFS0bits.T1IF = 0 ; // clear TMR1 overflow interrupt flag
IEC0bits.T1IE = 1 ; // enable interrupt on TMR1 overflow
Lcd_Custom_Config(&PORTD,7,6,5,4,&PORTD,2,0,3);
Lcd_Custom_Cmd(LCD_CLEAR);
Lcd_Custom_Cmd(LCD_CURSOR_OFF);
Lcd_Custom_Out(1, 1, "Volt is :");
// init ARP cache
memset(&arpCache, 0, sizeof(arpCache)) ;
/*
* initialize ethernet board
* start ENC28J60 with :
* reset bit on RG13
* CS bit on RG12
* my MAC & IP address
* full duplex
*/
Spi2_Init();
Spi2_Init_Advanced(_SPI_MASTER, _SPI_16_BIT, _SPI_PRESCALE_SEC_8, _SPI_PRESCALE_PRI_1, _SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_ACTIVE_2_IDLE);
SPI_Ethernet_Init(&PORTG, 13, &PORTG, 12, macAddr, ipAddr, SPI_Ethernet_FULLDUPLEX) ;
while(1) // endless loop
{
adcRes = Adc1_Read(1, ADC_12bit);
WordToStr(adcRes, text);
Lcd_Custom_Out(1, 10, text);
WordToStr(adcRes, udpStr) ; // read PORTB value and convert to string
Lcd_Custom_Out(2, 1, udpStr);
SPI_Ethernet_doPacket() ; // process incoming Ethernet packets
if(transmit && (tmr > 15)) // transmit one UDP packet per second
{
sendUDP(destIpAddr, 3456, destPortNum, udpStr, sizeof(udpStr)) ; // send to remote host
tmr = 0 ; // reset timer
}
}
}
|
|
|
| Back to top |
|
mbluethunder7000
Joined: 24 May 2008 Posts: 7 Location: Egypt
|
Posted: Sat Jun 07, 2008 10:17 am Post subject: |
|
|
Hi BrunoG
I would like to ask about some issues in you codes plus some general notes and I hope you could help me.
1: After revise your code carefully; I saw that you make three major sections, One for ARP Resolution, One for Send UDP Packet and one for Spi_ethernet_userUDP. So why you did use the ARP resolution to send the UDP packets instead of using the library of ARR which is exist in MikroC (ARPGet, ARPPut & ARPInit) and what is the important of using the ARP code to do that?
---------------------------------------
2: Regarding the UDP code, Why you didn’t use the MikroC library (UDPInit, UDPOpen, UDPClose, UDPIsPutReady, UDPPut, UDPFlush, UDPIsGetReady, UDPGet, UDPDiscard, UDPProcess, UDPWrite, UDPRead & UDPOpenSocket). Is this library not useful in your case or what?
------------------------------------
3: In the part of (Spi_ethernet_userUDP), you wrote this statement [/*save remote UDP host and port number, then reply with 'Start']. I don’t understand the part of (reply with ‘start’). Could you please explain?
Also, If the importance of this part is to save the remote host IP and remote host port number. Why you are using it while you’re already use the same IP and port number which are stored in macAddr & ipAddr?
Also, Could we use this section to send data after (begin) or not?
-------------------------------------------------------------------
4: This part (
| Quote: |
#define TRANSMIT_START 0x19AE
#define REPLY_START (TRANSMIT_START + 1)
|
If you mean the RAM of ENC by this area, Why you start from (0x19AE) while that we can start from 0x0000h?
-----------------------------------------------------------------
5: what is the aim from this part?
| Quote: |
// step in ARP cache
for(i = 0 ; i < ARPCACHELEN; i++)
{
// oldest slots must expire
if(arpCache[i].tmr < longTmr - 1000) // too old ?
{
arpCache[i].tmr = 0 ; // clear timer
arpCache[i].valid = 0 ; // disable slot
}
// is it the address I want in a valid slot ?
if(arpCache[i].valid && (memcmp(arpCache[i].ip, ip, 4) == 0))
{
return(arpCache[i].mac) ; // yes, return ready to use MAC addr
}
// find older slot, will be needed further
if(arpCache[i].tmr < tmrSlot)
{
tmrSlot = arpCache[i].tmr ; // save best timer
freeSlot = i ; // save best index
}
}
|
Because I notice that if I don’t use the ENC. It disconnects from the pc after time and I need to make PING process to let the PC see the ENC board again.
---------------------------------------------------------------------
6: I couldn’t understand this part, Why you are using the broadcast destination mac while my pc is not this MAC ? Shall I change it or not?
| Quote: |
Spi_Ethernet_memcpy(REPLY_START, "\xff\xff\xff\xff\xff\xff", 6) ; // destination is broadcast
|
------------------------------------------------------
7: I don’t understand why you are using (8, 6) as an ARP protocol? And how you could decided this?
| Quote: |
Spi_Ethernet_writeMemory(REPLY_START + 12, 8, 6, 1) ; // protocol is ARP
|
-------------------------------------------------------------
8: I don’t understand this, what is the aim of it?
| Quote: |
/*
* 0, 1 : hardware type = ethernet
* 8, 0 : protocole type = ip
* 6, 4 : HW size = 6, protocol size = 4
* 0, 1 : ARP opcode = request
*/
|
Also, this part:
| Quote: |
Spi_Ethernet_memcpy(REPLY_START + 14, "\x0\x01\x08\x00\x06\x04\x00\x01", ;
|
| Quote: |
Spi_Ethernet_memcpy(REPLY_START + 32, "\0\0\0\0\0\0", 6) ; // mac addr destination : broadcast addr
|
| Quote: |
if((Spi_Ethernet_memcmp(REPLY_START + 12, "\x08\x06\x00\x01\x08\x00\x06\x04\x00\x02", 10) == 0)
|
--------------------------------
I am using this code to transmit the analogue signal (12bit) to PC. And I need to take this value to appear as volt (3.3V) while I am using the (WrodtoStr) converter and (4095) appear on the LCD as 3.3V
I will be highly appreciated of you could help me in this because it is a very important to me these days.
Waiting your reply |
|
| Back to top |
|
BrunoG Site Admin
Joined: 22 Nov 2005 Posts: 636
|
Posted: Sat Jun 07, 2008 10:21 pm Post subject: |
|
|
Hi,
I supposed you are confused because you are trying to mix
Advanced SPI Ethernet Library for dsPIC
with
SPI Ethernet Library for dsPIC
and with my own functions, which refers to the early mikroC SPI Ethernet library for PIC.
I suggest you to select the library the most appropriate to your needs. _________________ BrunoG, Administrator |
|
| Back to top |
|
mbluethunder7000
Joined: 24 May 2008 Posts: 7 Location: Egypt
|
Posted: Sat Jun 07, 2008 11:49 pm Post subject: |
|
|
| BrunoG wrote: | Hi,
I supposed you are confused because you are trying to mix
Advanced SPI Ethernet Library for dsPIC
with
SPI Ethernet Library for dsPIC
and with my own functions, which refers to the early mikroC SPI Ethernet library for PIC.
I suggest you to select the library the most appropriate to your needs. |
Actually I need something easy to be used and to be understood and let me achieve needs. I need only to send the analogue data from (AN1) to UDP terminal.
The difficult part to me is the Ethernet concept because if this issue is belong only to the hardware of the dsPIC so I can easy handle it, But Ethernet issue is consists of several aspects and standards which i don’t know to achieve my needs
I understood that you make special functions in your codes. I hardly tried several times to find a something useful can match the dsPIC not PIC but I didn't found that.
When I saw your codes I said that it could help me and achieves my needs of course with some extra help from your side.
Actually I am confused because of this issue and I don’t know who I can make it correctly. So, shall I expect help from your side in this issue or not? You are expert in this field . |
|
| Back to top |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|