
PIC16C74 Embedded 10BaseT Ethernet CS8900
Embedded ethernet enables microcontroller based projects to send and receive packets over the network. The board shown on the left is actual size and incorporates all the circuitry needed to enable 10BaseT communications. The board is designed to minimize... Electronics Projects, PIC16C74 Embedded 10BaseT Ethernet CS8900 "microchip projects, microcontroller projects, " Date 2019/08/02
Embedded ethernet enables microcontroller based projects to send and receive packets over the network. The board shown on the left is actual size and incorporates all the circuitry needed to enable 10BaseT communications. The board is designed to minimize the pin count needed to interface with microcontrollers. An 8 bit data bus, 4 bit address bus, and three control signals (15 signals) with an optional interrupt signal are all that is needed to control the board. This is made possible by using the Crystal CS8900 ethernet transceiver running in 8-bit mode. All the information, schematics, and source code needed to perform TCP/IP communication over ethernet is detailed on this page. I’m using a Microchip PIC16C74 controller in this project however, any controller with enouph port capacity will also work. This would include the popular Motarola 68HC11.
The project described here is in two parts. The actual embedded ethernet board and the test circuit utilizing the PIC16C74. The code running on the PIC incorporates the necessary drivers for the board along with the TCP/IP layers needed to communicate on the network.
Overview of the Crystal CS8900
The Crystal CS8900 is a single chip solution capable of interfacing directly to the analog side of 10BaseT ethernet using only an isolation transformer and some passive components. The CS8900 has 4K of integrated memory allowing it to receive and send packets asynchronous to the microcontroller. This eliminates any timing issues that would normally be present and allows even the slowest microcontroller to talk on the ethernet. The CS8900 itself, is running at 20Mhz and requires an external crystal. Most ethernet transceivers operate directly on the ISA bus and use DMA to access external RAM for incoming and outgoing packets and control information. The Crystal part also operates in this mode but also has an 8 bit mode. Using this mode is similar to controlling ports in the PC architecture. For a write operation, the address is placed on the address bus, say 0x300, the data is placed on the data bus and then and then the /IOW signal is toggled. Address decode logic on one of the boards “sees” that it’s there port address (0x300) and then grabs the data from the data bus. For a read operation, the address, 0x300, is placed on the address bus and the /IOR signal is toggled, the card with this address places the data on the bus for the “in” instruction to read. This is how the CS8900 works in 8 bit mode and the default starting address for port access is 0x300 and continues to 0x30F. Notice that only 4 bits are really needed on the address bus to address all the register locations.
Other address bus pins are tied either high or low. By manipulating these 16 register locations, you can control the entire 4K of internal memory known as PacketPage memory. Essentially, the CS8900 incorporates and indirect set of registers for controlling a much larger 4K area of internal memory on the part. For example, the documentation states that the length of the frame received is at location 0x0402 and 0x0403 (The CS8900 always uses 16 bit values) so you place the value 0x0402 into the PacketPage pointer location (0xa and 0xb) and read the data from the PacketPage data location (0xc and 0xd). The actual data you’re reading is coming from the 0x0402 and 0x0403 locations within PacketPage memory. This technique is more completely described in the Crystal application note AN112.
Schematic of the embedded ethernet card shown above
This board was designed using ExpressPCB. The software for board layout design can be downloaded for free from their website and the ordering of boards is automated though the software package.
It should be mentioned that you will need to use a professionaly designed board for this project since the CS8900 is only available in a 100 pin QFP surface mount package. Don’t panic! I didn’t know anything about surface mount technology until I started this project, either. Here’s the technique I use to solder the chip to the board:
• Use a 3x/4x magnifying lamp.
• Get a soldering iron that has adjustable temperature settings, use 450-500 degrees farenheit.
• Since the CS8900 uses .020 inch spaced leads, use a tip that has a diameter less than this, I use a .015 inch tip.
• Get some flux at Radio Shack and place a very small amount on the surface mount pads.
• Get some silicon-based adhesive from Radio Shack and place a small amount on the belly of the CS8900. This will allow you to place the part and center it over the pads. Take your time and go slow.
• When the silicon hardens, heat up the iron and on the outer-edge pins, place your iron on the pad and allow a small amount of solder to flow. What we’re trying to do here is anchor the part on the four sides. Repeat for each side.
• From this point on, don’t use ANY SOLDER. The board as manufactured by ExpressPCB has been tin-lead plated and the pads already contain all the solder necessary to form a good inter-metalic bond. Merely touch the iron to each pin and allow the solder to reflow. This goes very fast and you can solder all the remaining 96 pins in under 5 minutes.
Overview of the test circuit A Microchip PIC16C74 is used to drive the CS8900 and to implement some basic TCP/IP functionallity. The test circuit, once connected to the ethernet backbone, can be pinged from another node. Also, a Windows Sockets program is included that connects to the test circuit who is listening on UDP port 7 (echo). The echo service sends back any data that it receives.
The programs are all setup to use IP address 192.168.1.2 and Ethernet address (also called an OUI- Organizationally Unique Identifier) of 00:00:00:12:34:56. Since these are ficticious numbers, you may need to change them. Two places that need modification, the program running on the PIC has equates for these values and the IP address is hard coded in the testudp.c program. If you don’t change them, and are testing under NT (recommended) you may need to add a static route using the command route add 192.168.1.2 your.ip.gateway.address. This will cause all traffic to the board to go through the default gateway of you’re local machine.
Schematic of the test circuit
In conclusion: I originally worked on this project in anticipation of selling the technology but circumstances changed and I hope that the embedded community will benifit from this work. Embedded ethernet is not without it’s problems. For example. I was planning on using an EEPROM as the storage for packet data but quickly realized that the write/erase times would not be sufficient. Typical write times are 5ms which brought the ping time for a 500 byte packet to 1.5 seconds. I believe now that the key to using this technology is to write specifically to the problem domain.
By Gary T. Desrosiers
Copyright © Gary T. Desrosiers, 1998
Embedded 10BaseT Ethernet PCB files (express pcb)
FILE DOWNLOAD LINK LIST (in TXT format): LINKS-5431.zip
Embedded 10BaseT Ethernet Assembly code
list p=pic16c74 __config h'3ffa' ;HS crystal, 20Mhz include; ; *Change these* : Configuration equates. ; IP1 equ d'192' ;first octet of IP address IP2 equ d'168' ;second octet of IP address IP3 equ d'1' ;third octet of IP address IP4 equ d'2' ;fourth octet of IP address ; MAC1 equ 0x00 ;\ MAC2 equ 0x00 ; \ MAC3 equ 0x00 ; \ MAC4 equ 0x12 ; 48 bit IEEE OUI (Organizationally Unique Identifier) MAC5 equ 0x34 ; / MAC6 equ 0x56 ;/ ; ; Some useful macros ; ppRD macro addr ;Read PacketPage port movlw addr&0xff movwf offsetL movlw addr>>8 movwf offsetH call ReadPP endm ; ppWR macro addr,val ;Write PacketPage port movlw addr&0xff movwf offsetL movlw addr>>8 movwf offsetH movlw val&0xff movwf valueL movlw val>>8 movwf valueH call WritePP endm ; Dinput macro ;Change the data bus to input bsf STATUS,RP0 movlw 0xff movwf TRISB bcf STATUS,RP0 endm ; Doutput macro ;Change the data bus to output bsf STATUS,RP0 clrf TRISB bcf STATUS,RP0 endm ; ior macro port ;I/O port read movlw port call ioRead endm ; iow macro port ;I/O port write movwf PORTB movlw port movwf PORTA call ioWrite endm ; ; Crystal CS8900 PacketPage equates ; portRxTxData equ 0x00 ;Receive/Transmit data (port 0) portRxTxData1 equ 0x02 ;Receive/Transmit data (port 0) portTxCmd equ 0x04 ;Transmit Commnad portTxLength equ 0x06 ;Transmit Length portISQ equ 0x08 ;Interrupt status queue portPtr equ 0x0a ;PacketPage pointer portData equ 0x0c ;PacketPage data (port 0) portData1 equ 0x0e ;PacketPage data (port 1) ; ; CS8900 PacketPage Offsets ; ppEISA equ 0x0000 ;EISA Registration number of CS8900 ppProdID equ 0x0002 ;Product ID Number ppIOBase equ 0x0020 ;I/O Base Address ppIntNum equ 0x0022 ;Interrupt number (0,1,2, or 3) ppMemBase equ 0x002C ;Memory Base address register (20 bit) ppRxCfg equ 0x0102 ;Receiver Configuration ppRxCtl equ 0x0104 ;Receiver Control ppTxCfg equ 0x0106 ;Transmit Configuration ppBufCfg equ 0x010A ;Buffer Configuration ppLineCtl equ 0x0112 ;Line Control ppSelfCtl equ 0x0114 ;Self Control ppBusCtl equ 0x0116 ;Bus Control ppTestCtl equ 0x0118 ;Test Control ppISQ equ 0x0120 ;Interrupt status queue ppRxEvt equ 0x0124 ;Receiver Event ppTxEvt equ 0x0128 ;Transmitter Event ppBufEvt equ 0x012C ;Buffer Event ppRxMiss equ 0x0130 ;Receiver Miss Counter ppTxCol equ 0x0132 ;Transmit Collision Counter ppLineSt equ 0x0134 ;Line Status ppSelfSt equ 0x0136 ;Self Status ppBusSt equ 0x0138 ;Bus Status ppTxCmd equ 0x0144 ;Transmit Command Request ppTxLength equ 0x0146 ;Transmit Length ppIndAddr equ 0x0158 ;Individual Address (IA) ppRxStat equ 0x0400 ;Receive Status ppRxLength equ 0x0402 ;Receive Length ppRxFrame equ 0x0404 ;Receive Frame Location ppTxFrame equ 0x0A00 ;Transmit Frame Location ; ; Register Numbers ; REG_NUM_MASK equ 0x003F REG_NUM_RX_EVENT equ 0x0004 REG_NUM_TX_EVENT equ 0x0008 REG_NUM_BUF_EVENT equ 0x000C REG_NUM_RX_MISS equ 0x0010 REG_NUM_TX_COL equ 0x0012 ; ; Self Control Register ; SELF_CTL_RESET equ 0x0040 SELF_CTL_HC1E equ 0x2000 SELF_CTL_HCB1 equ 0x8000 ; ; Self Status Register ; SELF_ST_INIT_DONE equ 0x0080 SELF_ST_SI_BUSY equ 0x0100 SELF_ST_EEP_PRES equ 0x0200 SELF_ST_EEP_OK equ 0x0400 SELF_ST_EL_PRES equ 0x0800 ; ; Bus Control Register ; BUS_CTL_USE_SA equ 0x0200 BUS_CTL_MEM_MODE equ 0x0400 BUS_CTL_IOCHRDY equ 0x1000 BUS_CTL_INT_ENBL equ 0x8000 ; ; Bus Status Register ; BUS_ST_TX_BID_ERR equ 0x0080 BUS_ST_RDY4TXNOW equ 0x0100 ; ; Line Control Register ; LINE_CTL_RX_ON equ 0x0040 LINE_CTL_TX_ON equ 0x0080 LINE_CTL_AUI_ONLY equ 0x0100 LINE_CTL_10BASET equ 0x0000 ; ; Test Control Register ; TEST_CTL_DIS_LT equ 0x0080 TEST_CTL_ENDEC_LP equ 0x0200 TEST_CTL_AUI_LOOP equ 0x0400 TEST_CTL_DIS_BKOFF equ 0x0800 TEST_CTL_FDX equ 0x4000 ; ; Receiver Configuration Register ; RX_CFG_SKIP equ 0x0040 RX_CFG_RX_OK_IE equ 0x0100 RX_CFG_CRC_ERR_IE equ 0x1000 RX_CFG_RUNT_IE equ 0x2000 RX_CFG_X_DATA_IE equ 0x4000 ; ; Receiver Event Register ; RX_EVENT_RX_OK equ 0x0100 RX_EVENT_IND_ADDR equ 0x0400 RX_EVENT_BCAST equ 0x0800 RX_EVENT_CRC_ERR equ 0x1000 RX_EVENT_RUNT equ 0x2000 RX_EVENT_X_DATA equ 0x4000 ; ;Receiver Control Register ; RX_CTL_RX_OK_A equ 0x0100 RX_CTL_MCAST_A equ 0x0200 RX_CTL_IND_A equ 0x0400 RX_CTL_BCAST_A equ 0x0800 RX_CTL_CRC_ERR_A equ 0x1000 RX_CTL_RUNT_A equ 0x2000 RX_CTL_X_DATA_A equ 0x4000 ; ;Transmit Configuration Register ; TX_CFG_LOSS_CRS_IE equ 0x0040 TX_CFG_SQE_ERR_IE equ 0x0080 TX_CFG_TX_OK_IE equ 0x0100 TX_CFG_OUT_WIN_IE equ 0x0200 TX_CFG_JABBER_IE equ 0x0400 TX_CFG_16_COLL_IE equ 0x8000 TX_CFG_ALL_IE equ 0x8FC0 ; ;Transmit Event Register ; TX_EVENT_TX_OK equ 0x0100 TX_EVENT_OUT_WIN equ 0x0200 TX_EVENT_JABBER equ 0x0400 TX_EVENT_16_COLL equ 0x1000 ; ; Transmit Command Register ; TX_CMD_START_5 equ 0x0000 TX_CMD_START_381 equ 0x0080 TX_CMD_START_1021 equ 0x0040 TX_CMD_START_ALL equ 0x00C0 TX_CMD_FORCE equ 0x0100 TX_CMD_ONE_COLL equ 0x0200 TX_CMD_NO_CRC equ 0x1000 TX_CMD_NO_PAD equ 0x2000 ; ;Buffer Configuration Register ; BUF_CFG_SW_INT equ 0x0040 BUF_CFG_RDY4TX_IE equ 0x0100 BUF_CFG_TX_UNDR_IE equ 0x0200 ; ; PORTA pin assignments (Crystal address bus) ; SA0 equ 0 SA1 equ 1 SA2 equ 2 SA3 equ 3 ;RA4 equ 4 ;not used (ST) ;RA5 equ 5 ;not used (TTL) ; ; PORTB pin assignments (Crystal data bus) ; SD0 equ 0 SD1 equ 1 SD2 equ 2 SD3 equ 3 SD4 equ 4 SD5 equ 5 SD6 equ 6 SD7 equ 7 ; ; PORTC pin assignments (Crystal signals CHIPSEL/IOW/IOR) ; IOR equ 0 ;active low signal to initiate I/O read operation IOW equ 1 ;active low signal to initiate I/O write operation CHIPSEL equ 2 ;active low signal to select the CS8900 chip INTR equ 3 ;active HIGH interrupt pending signal. Auto cleared after read of ISQ ;RC4 equ 4 ;not used (ST) ;RC5 equ 5 ;not used (ST) ;RC6 equ 6 ;not used (ST) ;RC7 equ 7 ;not used (ST) ; ; PORTD pin assignments ; ;RD0 equ 0 ;not used ;RD1 equ 1 ;not used ;RD2 equ 2 ;not used ;RD3 equ 3 ;not used ;RD4 equ 4 ;not used ;RD5 equ 5 ;not used ;RD6 equ 6 ;not used ;RD7 equ 7 ;not used ; ; PORTE pin assignments (LCD control) ; ;RE0 equ 0 ;not used ;RE1 equ 1 ;not used ;RE2 equ 2 ;not used ; ; Register file assignments ; tempH equ 0x20 tempL equ 0x21 loops equ 0x22 loops2 equ 0x23 loops3 equ 0x24 char equ 0x25 cnt_low equ 0x26 cnt_mid equ 0x27 cnt_hi equ 0x28 bcd1 equ 0x29 bcd2 equ 0x2a bcd3 equ 0x2b valueH equ 0x2c valueL equ 0x2d offsetH equ 0x2e offsetL equ 0x2f flags equ 0x30 hextemp equ 0x31 lengthH equ 0x32 lengthL equ 0x33 packet equ 0x34 ;the highest register file location is 3F because we need 64 bytes after this. ; ; Packet offset equates ; ; ; Packet header ; pktLenH equ 0x00 pktLenL equ 0x01 pktDest0H equ 0x02 pktDest0L equ 0x03 pktDest1H equ 0x04 pktDest1L equ 0x05 pktDest2H equ 0x06 pktDest2L equ 0x07 pktSrc0H equ 0x08 pktSrc0L equ 0x09 pktSrc1H equ 0x0a pktSrc1L equ 0x0b pktSrc2H equ 0x0c pktSrc2L equ 0x0d pktTypeH equ 0x0e pktTypeL equ 0x0f ; ; ARP ; ar_hwtype equ 0x10 ;hardware type ar_prtype equ 0x12 ;protocol type ar_hwlen equ 0x14 ;hardware address length ar_prlen equ 0x15 ;protocol address length ar_op equ 0x16 ;ARP operation (1=request, 2=reply) ar_sha equ 0x18 ;senders hardware address ar_spa equ 0x1e ;senders IP address ar_tha equ 0x22 ;target hardware address ar_tpa equ 0x28 ;target IP address ; ; IP header ; ip_verlen equ 0x10 ;IP version and header length(in longs) ip_tos equ 0x11 ;IP type of service ip_len equ 0x12 ;packet length (length-header_length) ip_id equ 0x14 ;datagram id ip_fragoff equ 0x16 ;fragment offset ip_ttl equ 0x18 ;time to live (in gateway hops) ip_proto equ 0x19 ;protocol (ICMP=1, TCP=6, EGP=8, UDP=17) ip_cksum equ 0x1a ;header checksum ip_src equ 0x1c ;IP address of source ip_dst equ 0x20 ;IP addess of destination ip_data equ 0x24 ; ; IP value equates ; IPT_ICMP equ 1 ;protocol type for ICMP packets IPT_TCP equ 6 ;protocol type for TCP packets IPT_EGP equ 8 ;protocol type for EGP packets IPT_UDP equ 0x11 ;protocol type for UDP packets ; ; ICMP header ; ic_type equ ip_data ;0=reply, 8=request, others=who-cares ic_code equ ic_type+1 ;code ic_cksum equ ic_code+1 ;checksum of header+data ic_id equ ic_cksum+2 ;message id ic_seq equ ic_id+2 ;sequence number ; ; UDP Header ; u_src equ ip_data ;source udp port number u_dst equ u_src+2 ;destination UDP port number u_len equ u_dst+2 ;length of UDP header+data u_cksum equ u_len+2 ;checksum (see note) u_data equ u_cksum+2 ;start of data ; ; Note: checksum is calculated by taking the 16 bit sums of the ip_src, ip_dst, ; ip_proto, u_len, and the sum starting at u_src for a length of u_len ; yes, this means that u_len is taken twice! u_cksum is zero during the calc. ; The sum is then one's complemented. This is the checksum ; org 0 goto start ; org 4 retfie ; start bsf STATUS,RP0 movlw 0xff ;make all RA/RE movwf ADCON1 ;pins digital I/O clrf TRISA ;crystal address bus output clrf TRISB ;crystal data bus output clrf TRISC ;crystal control signals output bcf STATUS,RP0 bsf PORTC,IOR ;no read on crystal bsf PORTC,IOW ;no write on crystal bsf PORTC,CHIPSEL ;address enable clrf PORTA ;clear address bus call VerChip call ResetChip call InitChip clrf flags loop btfss PORTC,INTR ;wait for interrupt goto loop call ProcessISQ btfss flags,0 ;received frame flag goto loop bcf flags,0 ;clear the receive flag btfss flags,1 ;bit set when valid arp goto loop bcf flags,1 ;clear the valid arp request flag call SendARP goto loop ; ; wait for W milliseconds ; wait movwf loops wait0 movlw 5 movwf loops2 wait1 movlw .110 movwf loops3 wait2 nop nop nop nop nop nop decfsz loops3,1 goto wait2 decfsz loops2,1 goto wait1 decfsz loops,1 goto wait0 return ; ; Compare two 16 bit numbers and return the result in STATUS,C ; If C=0, valueH/valueL is less than tempH/tempL ; if C=1, then valueH/valueL is greater than or equal to tempH/tempL ; valueH/valueH are destroyed in the process. cmp16 movf tempL,0 ;get low subwf valueL,1 btfsc STATUS,C ;C=0 means its neg goto cmpH ;C=1, valueL is >= 0x7f movlw 1 subwf valueH,1 ;decrement high btfss STATUS,C ;if it goes neg, then goto cmpIsLess ; value is less than 0x7f cmpH movf tempH,0 ;0x00 part of 0x007f subwf valueH,1 ;subtract btfss STATUS,C goto cmpIsLess bsf STATUS,C ; valueH/valueL is greater or equal to tempH/tempL return cmpIsLess bcf STATUS,C ;valueH/valueL is less than 0x007F return ;************************************************************************ ;* C S 8 9 0 0 D r i v e r F u n c t i o n s * ;************************************************************************ ; ; SendARP - Send a response ARP to the requestor ; SendARP Doutput movlw TX_CMD_START_ALL iow portTxCmd movlw 0 iow portTxCmd+1 movlw d'42' ;length of ARP response frame iow portTxLength movlw 0 iow portTxLength+1 RTGetStat ppRD ppBusSt ;get BusStatus btfss valueH,0 ;is BUS_ST_RDY4TXNOW (ready for transmit) goto RTGetStat ;no, wait for it Doutput ; Send dest (6) movf packet+pktSrc0H,0 iow portRxTxData movf packet+pktSrc0L,0 iow portRxTxData+1 movf packet+pktSrc1H,0 iow portRxTxData movf packet+pktSrc1L,0 iow portRxTxData+1 movf packet+pktSrc2H,0 iow portRxTxData movf packet+pktSrc2L,0 iow portRxTxData+1 ; Send src (6) movlw MAC1 iow portRxTxData movlw MAC2 iow portRxTxData+1 movlw MAC3 iow portRxTxData movlw MAC4 iow portRxTxData+1 movlw MAC5 iow portRxTxData movlw MAC6 iow portRxTxData+1 ; Send type (2) movlw 0x08 iow portRxTxData movlw 0x06 iow portRxTxData+1 ; Send hwtype (2) movlw 0x00 iow portRxTxData movlw 0x01 iow portRxTxData+1 ; Send prtype (protocol type) (2) movlw 0x08 iow portRxTxData movlw 0x00 iow portRxTxData+1 ; Send hardware and protocol address lengths (2) movlw 0x06 iow portRxTxData movlw 0x04 iow portRxTxData+1 ; Send operation (response) (2) movlw 0x00 iow portRxTxData movlw 0x02 iow portRxTxData+1 ; Send Senders HW address (6) movlw MAC1 iow portRxTxData movlw MAC2 iow portRxTxData+1 movlw MAC3 iow portRxTxData movlw MAC4 iow portRxTxData+1 movlw MAC5 iow portRxTxData movlw MAC6 iow portRxTxData+1 ; Send Senders IP (4) movlw IP1 iow portRxTxData movlw IP2 iow portRxTxData+1 movlw IP3 iow portRxTxData movlw IP4 iow portRxTxData+1 ; Send Target HW address (6) movf packet+pktSrc0H,0 iow portRxTxData movf packet+pktSrc0L,0 iow portRxTxData+1 movf packet+pktSrc1H,0 iow portRxTxData movf packet+pktSrc1L,0 iow portRxTxData+1 movf packet+pktSrc2H,0 iow portRxTxData movf packet+pktSrc2L,0 iow portRxTxData+1 ; Send Target IP (4) movf packet+ar_spa,0 iow portRxTxData movf packet+ar_spa+1,0 iow portRxTxData+1 movf packet+ar_spa+2,0 iow portRxTxData movf packet+ar_spa+3,0 iow portRxTxData+1 return ; ; ; ; Receive Event ; Input with RxEvent in valueH ; ReceiveEvent Dinput ;make data bus input ; ; It's important to read the status and length high-order ; byte first. ; ior portRxTxData+1 ;read and discard status ior portRxTxData ;read and discard status movlw packet+2 ;set indirect movwf FSR ; address ior portRxTxData+1 ;get length high movwf packet+pktLenH ;save in header area movwf lengthH ; and in lengthH movwf valueH ;save for compare ior portRxTxData ;get length low movwf packet+pktLenL ;save in header area movwf lengthL ; and in lengthL movwf valueL ;save for compare ReadFrame movlw 0x7f-packet ;this is the max packet length addlw packet subwf FSR,0 btfsc STATUS,C goto RFCont ;done ; if C=0 (FSR-packet+64 is neg) then we have not received max bytes yet so write to register file ior portRxTxData ;read from CS8900 movwf INDF ;write it to file register incf FSR,1 ;increment file location ior portRxTxData+1 ;read from CS8900 movwf INDF ;write it to file register incf FSR,1 ;increment file location goto RFCont ;continue RFCont movlw 2 subwf lengthL,1 btfsc STATUS,C ;see if negative (C=0) goto RF1 ;C set so result is zero or better movlw 1 subwf lengthH,1 ;decrement high btfss STATUS,C goto ReadDone ;high went neg, we're done RF1 movf lengthL,0 ;get low btfss STATUS,Z goto ReadFrame ;not zero, continue movf lengthH,0 btfss STATUS,Z goto ReadFrame ;not zero, continue ReadDone movlw 1 iorwf flags,1 ;flag frame read movlw 0x08 ;check if subwf packet+pktTypeH,0 ; packet type btfss STATUS,Z ; is 0x0806 (ARP) goto ChkIP ;no, check IP movlw 0x06 subwf packet+pktTypeL,0 btfsc STATUS,Z goto DoArp ChkIP movlw 0x08 ;check if subwf packet+pktTypeH,0 ; packet type btfss STATUS,Z ; is 0x0800 (IP) return ;no, just return movf packet+pktTypeL,0 btfsc STATUS,Z goto DoIP ;process IP packet return discard ppRD ppRxCfg movlw RX_CFG_SKIP iorwf valueL,1 call WritePP ;discard frame return ; ; It's an arp request, Could be a request or a response. ; ARP packets are small so the whole thing is always in ; the register file. ; DoArp movlw 0x01 ;make sure it's 1 subwf packet+ar_hwtype+1,0 ;compare to low btfss STATUS,Z return ;exit, bad request movlw 0x08 ;make sure it's 0x0800 subwf packet+ar_prtype,0 ;compare to high btfss STATUS,Z return ;exit, bad request movlw 0 ;make sure it's 0x0800 subwf packet+ar_prtype+1,0 ;compare to low btfss STATUS,Z return ;exit, bad request movlw 0x06 ;make sure it's 6 for hwlen subwf packet+ar_hwlen,0 ;compare to high btfss STATUS,Z return ;exit, bad request movlw 0x04 ;make sure it's 4 for protocol length subwf packet+ar_prlen,0 ;compare to low btfss STATUS,Z return ;exit, bad request movlw 0x01 ;make sure it's 0x0001 for arp request subwf packet+ar_op+1,0 ;compare to low btfss STATUS,Z return ;exit, bad request movlw IP1 ;First IP octet subwf packet+ar_tpa,0 btfss STATUS,Z return ;exit, bad request movlw IP2 ;second IP octet subwf packet+ar_tpa+1,0 btfss STATUS,Z return ;exit, bad request movlw IP3 ;Third IP octet subwf packet+ar_tpa+2,0 btfss STATUS,Z return ;exit, bad request movlw IP4 ;fourth IP octet subwf packet+ar_tpa+3,0 btfss STATUS,Z return ;exit, bad request ; If we got to here, then we have a valid ARP request for our IP address movlw 2 iorwf flags,1 return ; ; Process IP packet for ICMP or UDP requests ; DoIP movlw IPT_ICMP ;get protocol number for ICMP subwf packet+ip_proto,0 ;compare to this packet's proto btfsc STATUS,Z ;if zero, then it's ICMP goto DoICMP ;go process ICMP packet movlw IPT_UDP ;get protocol number for UDP subwf packet+ip_proto,0 ;compare to this packet's proto btfss STATUS,Z ;if zero, then it's ICMP return ;just return, we dont process this type DoUDP movlw 7 ;port we're listing for requests on subwf packet+u_dst+1,0 ;compare to UDP packet btfss STATUS,Z ;if zero, then it's echo port return ;otherwise, just return clrf packet+ip_cksum ;clear clrf packet+ip_cksum+1 ; checksum movf packet+ip_src,0 ;move movwf packet+ip_dst ; ip movf packet+ip_src+1,0 ; of movwf packet+ip_dst+1 ; source movf packet+ip_src+2,0 ; to movwf packet+ip_dst+2 ; dest movf packet+ip_src+3,0 movwf packet+ip_dst+3 movlw IP1 ;move movwf packet+ip_src ; our movlw IP2 ; ip movwf packet+ip_src+1 ; address movlw IP3 ; to movwf packet+ip_src+2 ; source movlw IP4 movwf packet+ip_src+3 movf packet+pktSrc0H,0 ;move movwf packet+pktDest0H ; mac src to dest movf packet+pktSrc0L,0 movwf packet+pktDest0L movf packet+pktSrc1H,0 ;move movwf packet+pktDest1H ; mac src to dest movf packet+pktSrc1L,0 movwf packet+pktDest1L movf packet+pktSrc2H,0 ;move movwf packet+pktDest2H ; mac src to dest movf packet+pktSrc2L,0 movwf packet+pktDest2L movlw MAC1 ;move movwf packet+pktSrc0H ; our movlw MAC2 ; MAC movwf packet+pktSrc0L ; address movlw MAC3 ; to movwf packet+pktSrc1H ; source movlw MAC4 movwf packet+pktSrc1L movlw MAC5 movwf packet+pktSrc2H movlw MAC6 movwf packet+pktSrc2L movlw d'20' movwf lengthL clrf lengthH movlw packet+ip_verlen call cksum movf valueH,0 movwf packet+ip_cksum ;save new checksum movf valueL,0 movwf packet+ip_cksum+1 movf packet+u_src,0 ;get src port movwf tempL movf packet+u_dst,0 ;put dest port movwf packet+u_src ;in source movf tempL,0 movwf packet+u_dst ;put source port in dest movf packet+u_src+1,0 ;get src port movwf tempL movf packet+u_dst+1,0 ;put dest port movwf packet+u_src+1 ;in source movf tempL,0 movwf packet+u_dst+1 ;put source port in dest clrf packet+u_cksum ;clear UDP checksum for new calc clrf packet+u_cksum+1 ;clear byte two clrf cnt_low clrf cnt_mid ;clear checksum accum clrf cnt_hi movlw packet+ip_src movwf FSR movlw d'8' ;IP_ALEN*2 call UDPCkSum movf packet+ip_proto,0 ;get protocol (1 byte) addwf cnt_low,1 ;add to accum btfss STATUS,C goto ProtoDone movlw 1 addwf cnt_mid,1 btfsc STATUS,C incf cnt_hi,1 ProtoDone movlw packet+u_len ;add in UDP len movwf FSR movlw d'2' call UDPCkSum movlw packet+u_src movwf FSR movf packet+u_len+1,0 call UDPCkSum movf cnt_hi,0 addwf cnt_low,1 btfsc STATUS,C incf cnt_mid,1 comf cnt_mid,0 movwf packet+u_cksum comf cnt_low,0 movwf packet+u_cksum+1 Doutput movlw TX_CMD_START_ALL iow portTxCmd movlw 0 iow portTxCmd+1 movf packet+pktLenL,0 ;length of ARP response frame iow portTxLength movf packet+pktLenH,0 iow portTxLength+1 UDPGetStat ppRD ppBusSt ;get BusStatus btfss valueH,0 ;is BUS_ST_RDY4TXNOW (ready for transmit) goto UDPGetStat ;no, wait for it Doutput btfss packet+pktLenL,0 goto WriteEven ;even # of bytes movf packet+pktLenL,0 ;get length addlw packet movwf FSR clrf INDF ;clear byte WriteEven movlw packet+2 movwf FSR movf packet+pktLenL,0 movwf tempL ;save length of send in temp WriteUDP movf INDF,0 iow portRxTxData incf FSR,1 movf INDF,0 iow portRxTxData+1 incf FSR,1 movlw 2 subwf tempL,1 btfsc STATUS,Z goto UDPDone btfsc STATUS,C goto WriteUDP UDPDone return ; ; Calc (cumulative) checksum of UDP header/data ; UDPCkSum movwf tempL ;save length of buffer bcf STATUS,C ;clear carry rrf tempL,1 ;/2 cuz we process 2 bytes at a time UDPCklp movf INDF,0 ;get next byte high movwf valueH ;save it incf FSR,1 ;increment to low byte movf INDF,0 ;get low incf FSR,1 ;increment addwf cnt_low,1 ;add to accum btfss STATUS,C goto UDPLcarry movlw 1 addwf cnt_mid,1 btfsc STATUS,C incf cnt_hi,1 UDPLcarry movf valueH,0 ;get the high again addwf cnt_mid,1 btfsc STATUS,C incf cnt_hi,1 decfsz tempL,1 goto UDPCklp return ; ; Process ICMP (ping) requests ; DoICMP ;we might want to check in the future for IA or broadcast requests clrf packet+ip_cksum clrf packet+ip_cksum+1 ;clear checksum movf packet+ip_src,0 ;move movwf packet+ip_dst ; ip movf packet+ip_src+1,0 ; of movwf packet+ip_dst+1 ; source movf packet+ip_src+2,0 ; to movwf packet+ip_dst+2 ; dest movf packet+ip_src+3,0 movwf packet+ip_dst+3 movlw IP1 ;move movwf packet+ip_src ; our movlw IP2 ; ip movwf packet+ip_src+1 ; address movlw IP3 ; to movwf packet+ip_src+2 ; source movlw IP4 movwf packet+ip_src+3 clrf packet+ic_cksum ;clear ICMP clrf packet+ic_cksum+1 ; checksum clrf packet+ic_type ;make type a reply clrf packet+ic_code ;clear code movf packet+pktSrc0H,0 ;move movwf packet+pktDest0H ; mac src to dest movf packet+pktSrc0L,0 movwf packet+pktDest0L movf packet+pktSrc1H,0 ;move movwf packet+pktDest1H ; mac src to dest movf packet+pktSrc1L,0 movwf packet+pktDest1L movf packet+pktSrc2H,0 ;move movwf packet+pktDest2H ; mac src to dest movf packet+pktSrc2L,0 movwf packet+pktDest2L movlw MAC1 ;move movwf packet+pktSrc0H ; our movlw MAC2 ; MAC movwf packet+pktSrc0L ; address movlw MAC3 ; to movwf packet+pktSrc1H ; source movlw MAC4 movwf packet+pktSrc1L movlw MAC5 movwf packet+pktSrc2H movlw MAC6 movwf packet+pktSrc2L movlw d'20' ;length of IP header movwf lengthL ;set length of clrf lengthH ; checksum calculation movlw packet+ip_verlen ;displacement to start of IP header call cksum ;calculate the checksum movf valueH,0 movwf packet+ip_cksum ;set new checksum movf valueL,0 movwf packet+ip_cksum+1 movf packet+ip_len,0 ;get length high movwf lengthH movlw d'20' ;ip header length subwf packet+ip_len+1,0 ;calc length of ICMP header+data movwf lengthL btfss STATUS,C decf lengthH,1 ;if prev sub went neg then dec high movlw packet+ic_type ;start of ICMP header call cksum movf valueH,0 ;set new checksum movwf packet+ic_cksum movf valueL,0 movwf packet+ic_cksum+1 Doutput movlw TX_CMD_START_ALL iow portTxCmd movlw 0 iow portTxCmd+1 movf packet+pktLenL,0 ;length of ICMP response frame iow portTxLength ; is the same as movf packet+pktLenH,0 ; the request. iow portTxLength+1 ICMPGetStat ppRD ppBusSt ;get BusStatus btfss valueH,0 ;is BUS_ST_RDY4TXNOW (ready for transmit) goto ICMPGetStat ;no, wait for it Doutput movlw packet+pktDest0H movwf FSR movf packet+pktLenL,0 ;length movwf lengthL ; to movf packet+pktLenH,0 ; send movwf lengthH WritePing movf INDF,0 ;get next byte incf FSR,1 iow portRxTxData movf INDF,0 ;get next byte incf FSR,1 iow portRxTxData+1 movlw 2 ;subtract subwf lengthL,1 ; two byte from length btfsc STATUS,C ;see if negative (C=0) goto WP1 ;C set so result is zero or better movlw 1 subwf lengthH,1 ;decrement high btfss STATUS,C ;c=0 means negative goto ICMPDone ;high went neg, we're done WP1 movf lengthL,0 ;get low btfss STATUS,Z goto WritePing ;not zero, continue movf lengthH,0 btfss STATUS,Z goto WritePing ;not zero, continue ICMPDone return ; ; Calc checksum. Reads packet at offset W for ; LengthH/LengthL bytes and calculates the checksum ; in valueH/valueL. ; cksum movwf FSR clrf cnt_low ;we do the arithmetic clrf cnt_mid ; using a 24 clrf cnt_hi ; bit area cksuml movf INDF,0 ;get high byte of 16-bit word movwf valueH ;save it incf FSR,1 movf INDF,0 incf FSR,1 addwf cnt_low,1 ;add to accum btfss STATUS,C goto noLcarry movlw 1 addwf cnt_mid,1 btfsc STATUS,C incf cnt_hi,1 noLcarry movf valueH,0 ;get the high again addwf cnt_mid,1 btfsc STATUS,C incf cnt_hi,1 ; movlw 2 ;subtract subwf lengthL,1 ; two byte from length btfsc STATUS,C ;see if negative (C=0) goto CK1 ;C set so result is zero or better movlw 1 subwf lengthH,1 ;decrement high btfss STATUS,C ;c=0 means negative goto CkDone ;high went neg, we're done CK1 movf lengthL,0 ;get low btfss STATUS,Z goto cksuml ;not zero, continue movf lengthH,0 btfss STATUS,Z goto cksuml ;not zero, continue ; CkDone movf cnt_hi,0 ;get the third byte of 24 bit area addwf cnt_low,1 ;any carries into this are added in btfsc STATUS,C ;if that caused a carry, then incf cnt_mid,1 ; increment the middle byte comf cnt_low,0 ;get and ones complement movwf valueL ;save it to low comf cnt_mid,0 ;get and ones complement movwf valueH ;save as high return ; ; Transmit Event ; TransmitEvent return ; ; Processes the pending interrupt requests from the Interrupt Status Queue ; ProcessISQ ; Read the ISQ NextEvt Dinput ior portISQ ;read interrupt status queue movwf valueL ;save value low ior portISQ+1 ;read interrupt status queue high movwf valueH ;save value high movf valueL,0 ;get val btfsc STATUS,Z return ;if zero, then done movlw REG_NUM_RX_EVENT subwf valueL,0 ;RxEvent? btfsc STATUS,Z goto evtRecv movlw REG_NUM_TX_EVENT subwf valueL,0 ;TxEvent? btfsc STATUS,Z ;Ingore BufEvent, RxMiss, and TxCol call TransmitEvent goto NextEvt evtRecv call ReceiveEvent goto NextEvt ; ; Initializes the chip ; InitChip ppWR ppLineCtl,LINE_CTL_10BASET ;set to 10BaseT ppWR ppTestCtl,TEST_CTL_FDX ;set to full duplex ppWR ppRxCfg,RX_CFG_RX_OK_IE ;enable RxOK interrupt ppWR ppRxCtl,(RX_CTL_RX_OK_A|RX_CTL_IND_A|RX_CTL_BCAST_A) ppWR ppTxCfg,TX_CFG_ALL_IE ; ; Important: The IA needs to be byte revered IA=aa:bb:cc:dd:ee:ff ; ppWR ppIndAddr,(MAC2<<8|MAC1) ;0xbbaa Write ppWR ppIndAddr+2,(MAC4<<8|MAC3) ;0xddcc out ppWR ppIndAddr+4,(MAC6<<8|MAC5) ;0xffee 48 bit IA ppWR ppIntNum,0x00 ;INT is on INTRQ0 ppRD ppBusCtl ;get Bus Control bsf valueH,7 ;enable irq call WritePP ;write it back ppRD ppLineCtl ;get Line Control bsf valueL,6 ;set SerRxOn bsf valueL,7 ;set SerTxOn call WritePP ;write it back return ; ; Resets the CS8900 ; ResetChip ppWR ppSelfCtl,SELF_CTL_RESET ;issue a reset to the chip ResetWait movlw d'1' ;wait for call wait ;a millisecond ppRD ppSelfCtl ;get the Self Control status btfsc valueL,6 ;see it bit 6 (RESET) was cleared goto ResetWait ;no, then still in reset, wait some more ppRD ppSelfSt ;get self status btfss valueL,7 ;bit 7 is INITD goto ResetWait ; when set, initialization of the CS8900 is done return ; ; Verifies that the CS8900 is attached and sets the STATUS,Z flag to ; indicate success or not set if failure. ; VerChip Dinput ;make the data bus input ; first, get the signature at portPtr which should be 0x3000 ior portPtr ;read PacketPage Ptr movwf valueL ;save value low ior portPtr+1 ;read PacketPage Ptr for high order byte movwf PORTA ;set the address bus movwf valueH ;save high low movf valueL,0 ;get low value btfss STATUS,Z ;should be 0 (i.e. 0x3000 low is 0x00) goto VerBad movlw 0x30 ;high part of 0x3000 subwf valueH,0 ;subtract from value obtained btfss STATUS,Z ;see if compared okay goto VerBad ppRD ppEISA ;get the EISA number whoch should be 0x630E movlw 0x63 subwf valueH,0 ;compare to 0x63 btfss STATUS,Z goto VerBad movlw 0x0e ;compare to 0x0e subwf valueL,0 btfss STATUS,Z goto VerBad ppRD ppProdID ;get the Product ID which should be 000x xxxx 0000 0000 ;where x xxxx = 0 0011 for rev E and 0 0101 for rev F movf valueL,0 ;set return status VerBad return ;return with status,z indicating success (Z) or not set for failure ; ; Writes the value at valueH/valueL to the PagePacket register who's ; address is in offsetH/offsetL ; WritePP Doutput ;make the data bus output movf offsetL,0 ;get the low order byte iow portPtr ;write to PacketPage Ptr movf offsetH,0 ;get the high order byte iow portPtr+1 ;write to PacketPage ptr movf valueL,0 ;get low order value to write iow portData ;write to PacketPage data movf valueH,0 ;get high order data iow portData+1 ;write to PacketPage data return ; ; Reads the PagePacket at offsetH/offsetL and returns the result in ; valueH/valueL. ; ReadPP Doutput ;make the data bus output movf offsetL,0 ;get the offset to read iow portPtr ;write to PacketPage Ptr movf offsetH,0 ;get the high order offset iow portPtr+1 ;PagePacket Pointer Register high byte Dinput ;make the data bus input ior portData ;read the PacketPage data movwf valueL ;save value low ior portData+1 ;read the high order byte movwf valueH ;save the high order byte value return ioRead movwf PORTA bcf PORTC,CHIPSEL bcf PORTC,IOR nop movf PORTB,0 bsf PORTC,IOR bsf PORTC,CHIPSEL return ; ioWrite bcf PORTC,CHIPSEL bcf PORTC,IOW nop bsf PORTC,IOW bsf PORTC,CHIPSEL return end
Embedded 10BaseT Ethernet C code
#include <winsock.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { char szBuf[256]; struct sockaddr_in sin; WSADATA wsaData; SOCKET s; int rc,i; if (WSAStartup(0x101,&wsaData) == SOCKET_ERROR) { printf("WSAStartup() failed, rc=%d\n",WSAGetLastError()); WSACleanup(); return -1; } sin.sin_addr.S_un.S_addr = inet_addr("192.168.1.2"); sin.sin_family = AF_INET; sin.sin_port = htons(7); s = socket(AF_INET,SOCK_DGRAM,0); if(s<0) { printf("Couldn't get a socket, rc=%d\n",WSAGetLastError()); WSACleanup(); return -1; } if(connect(s,(struct sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR) { printf("connect() failed, rc=%d\n",WSAGetLastError()); WSACleanup(); return -1; } for(i=0;i<5;i++) { wsprintf(szBuf,"Test %d",i+1); rc = send(s,szBuf,strlen(szBuf),0); if (rc == SOCKET_ERROR) { printf("send() failed,rc=%d\n",WSAGetLastError()); WSACleanup(); return -1; } printf("Sent Data [%s]\n",szBuf); rc = recv(s,szBuf,sizeof(szBuf),0 ); if (rc == SOCKET_ERROR) { printf("recv() failed, rc=%d\n",WSAGetLastError()); closesocket(s); WSACleanup(); return -1; } if (rc == 0) { printf("Server closed connection\n"); closesocket(s); WSACleanup(); return -1; } printf("Received %d bytes, data [%s] from the board\n",rc,szBuf); } closesocket(s); WSACleanup(); }
Feedback PWM Motor Control Circuit with PIC16F628 L298
Circuit L298 (bridge-mounted motor drive) and PIC16F628 microcontroller based on the stop, sudden stop, start, improve, finish, forward, rewind controls have brake position the motor generator to the state in case of falling energy battery again sending software in assembly language prepared. Asm. hex and isis proteus. DSN files available
Feedback motor drive circuit