|
|
View previous topic :: View next topic |
Author |
Message |
learner
Joined: 17 Mar 2010 Posts: 10
|
SPI Wiznet garbage |
Posted: Wed Mar 17, 2010 6:21 pm |
|
|
My project is very similar to:
http://www.ccsinfo.com/forum/viewtopic.php?t=40693&start=15&postdays=0&postorder=asc&highlight=wiznet
I have the same wiznet812 module and PIC18F4455 connected using SPI. I am having a problem that my wiznet writes and reads are not consistent. When I write data to 4 registers in Wiznet and read them back, I dont always read the same values, it's right some times and garbage at other times.
I am using PCH v4.066, 37489 as its in a school computer and I did notice people saying that anything below 4.070 is highly unstable, I dont know if that is causing the problem.
I have tried using spi_read() instead of spi_write(), resetting Wiznet before every write, used different spi clocks, changed delays, etc but the results have been the same.
I have pasted the code below and my result as seen on Serial I/O window.
Code: |
#include <18F4455.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN //needed for USB functionality
#use delay(clock=48000000) //needed for USB functionality
#include <usb_cdc.h> //needed to perform USB to SERIAL functionality
#rom int 0xf00000={1,2,3,4} //needed for USB functionality
#include <usb_bootloader.h>
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
// PIC pins assigned to W5100 signals.
#define W5100_CS PIN_B2
#define W5100_RESET PIN_B3
// W5100 Commands (from W5100 data sheet).
#define W5100_WRITE_CMD 0xF0
#define W5100_READ_CMD 0x0F
// W5100 Register addresses (from W5100 data sheet).
#define W5100_MR_REG 0x0000
#define W5100_GAR0_REG 0x0001
#define W5100_GAR1_REG 0x0002
#define W5100_GAR2_REG 0x0003
#define W5100_GAR3_REG 0x0004
// etc.
// This routine writes 1 byte of data to a W5100 register
//!// at the specified register address.
void w5100_write_reg(int16 addr, int8 data)
{
output_low(W5100_CS); delay_us(30);
spi_write(W5100_WRITE_CMD);
spi_write((addr&0xFF00)>> 8); // Send address msb
spi_write((addr&0x00FF)); // Send address lsb
spi_write((data&0x00FF)); // Write data to W5100
output_high(W5100_CS);delay_us(30);
}
int8 w5100_read_reg(int16 addr)
{
int8 retval;
output_low(W5100_CS);delay_us(30);
spi_write(W5100_READ_CMD);
spi_write((addr&0xFF00) >> 8); // Send address msb
spi_write((addr&0x00FF)); // Send address lsb
retval = spi_read(0); // Read data from W5100
output_high(W5100_CS);delay_us(30);
return(retval);
}
int8 gar0, gar1, gar2, gar3;
unsigned int8 status;
void main()
{
usb_cdc_init(); //configure the CDC driver
usb_init(); //start up the USB driver
// Initialize the W5100 chip select signal to the deselected state.
output_high(W5100_CS); delay_us(20);
// Reset the W5100 chip and then wait for the time
// specified in the W5100 data sheet.
output_low(W5100_RESET);
delay_us(10); // Minimum reset pulse width is 2 us
output_high(W5100_RESET);
delay_ms(25); // Maximum Plock delay time is 10 ms
// Setup the PIC's SPI module to work with the W5100 chip.
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_64);
// Display the results. Look on the terminal window
// to see if it's correct. Should be: 12 34 56 78
while(TRUE)
{
while(usb_cdc_connected())
{
usb_task();
// See if we can write to the Gateway Address Registers
// (GAR0-GAR3). Just fill them with some test data.
w5100_write_reg(W5100_GAR0_REG, 0x12);delay_us(15);
w5100_write_reg(W5100_GAR1_REG, 0x34);delay_us(15);
w5100_write_reg(W5100_GAR2_REG, 0x56);delay_us(15);
w5100_write_reg(W5100_GAR3_REG, 0x78);delay_us(15);
// Now read back the GAR registers.
gar0 = w5100_read_reg(W5100_GAR0_REG);delay_us(15);
gar1 = w5100_read_reg(W5100_GAR1_REG);delay_us(15);
gar2 = w5100_read_reg(W5100_GAR2_REG);delay_us(15);
gar3 = w5100_read_reg(W5100_GAR3_REG);delay_us(15);
// Send to Serial port monitor
printf(usb_cdc_putc,"Result: %X %X %X %X \n\r", gar0, gar1, gar2, gar3);
delay_ms(2000);
}
}
} |
Result:
Code: |
Result: F0 34 56 78
Result: 02 00 00 78
Result: 12 04 00 08
Result: 00 04 00 78
Result: 12 34 56 78
Result: 12 34 56 78
Result: FF 34 56 78
Result: FF 34 56 78
Result: 12 34 56 78
Result: 12 34 56 78
Result: F0 04 00 78
Result: F0 04 00 08
Result: F0 34 56 78
Result: F0 04 00 78
Result: 12 34 56 78
Result: 02 00 02 00
Result: 12 04 00 78
Result: FF 34 56 78
Result: F0 04 00 08
Result: F0 34 56 78
Result: F0 04 00 08
Result: FF 34 56 78
Result: F0 34 56 78
Result: F0 04 00 78
Result: F0 34 56 78
Result: FF 34 56 78
Result: 12 34 56 78
Result: 12 34 56 78
Result: FF 34 56 78
Result: FF 34 56 78
Result: 12 04 00 08
Result: 12 34 56 78
Result: 12 34 56 78
Result: 12 04 00 78
Result: 12 04 00 08
Result: 12 F0 56 78
Result: 12 F0 56 78
Result: 02 00 00 08
Result: F0 34 56 78
Result: 02 00 02 00
Result: 12 34 56 78
Result: 12 34 56 78
Result: 12 34 02 00
Result: 12 34 56 78
Result: FF 34 56 78
Result: 12 34 56 78
Result: FF 34 56 78
Result: 12 04 00 78
Result: FF 34 F0 78
Result: 02 00 00 08
Result: 02 00 02 00
Result: 12 34 56 78
Result: 12 34 56 02
Result: 12 34 56 78
Result: F0 04 00 08
Result: 00 34 00 78
Result: F0 04 00 78
|
|
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Thu Mar 18, 2010 10:59 am |
|
|
any suggestions anyone? plz do let me know if you need more information. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 18, 2010 12:01 pm |
|
|
Test the CDC interface. See if it's working. Put in some faked up data
in the "gar" variables and see if it gets back to the PC OK.
For testing, add the lines shown in bold below:
Quote: |
// Now read back the GAR registers.
gar0 = w5100_read_reg(W5100_GAR0_REG);delay_us(15);
gar1 = w5100_read_reg(W5100_GAR1_REG);delay_us(15);
gar2 = w5100_read_reg(W5100_GAR2_REG);delay_us(15);
gar3 = w5100_read_reg(W5100_GAR3_REG);delay_us(15);
// *** TESTING ***
gar0 = 0x89;
gar1 = 0xAB;
gar2 = 0xCD;
gar3 = 0xEF;
// Send to Serial port monitor
printf(usb_cdc_putc,"Result: %X %X %X %X \n\r", gar0, gar1, gar2, gar3);
delay_ms(2000); |
|
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Thu Mar 18, 2010 12:48 pm |
|
|
Yes, cdc is working. 'Read' means the data I'm reading from Wiznet, 'Test' means the values assigned directly to the variables:
Read: 12 04 00 08
Test: 89 AB CD EF
Read: F0 34 56 78
Test: 89 AB CD EF
Read: 02 00 02 00
Test: 89 AB CD EF
Read: 12 34 56 78
Test: 89 AB CD EF
Read: FF 34 56 78
Test: 89 AB CD EF
Read: 12 34 56 78
Test: 89 AB CD EF
Read: 12 04 00 78
Test: 89 AB CD EF |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 18, 2010 2:14 pm |
|
|
Do a further test. See if it's a problem with reading.
Write to the "gar" registers once, above the loop.
Then repeatedly read the registers. See if they always
return the same data, or if it's garbled occasionally.
Here is the modified code for this test:
Code: |
// See if we can write to the Gateway Address Registers
// (GAR0-GAR3). Just fill them with some test data.
w5100_write_reg(W5100_GAR0_REG, 0x12);delay_us(15);
w5100_write_reg(W5100_GAR1_REG, 0x34);delay_us(15);
w5100_write_reg(W5100_GAR2_REG, 0x56);delay_us(15);
w5100_write_reg(W5100_GAR3_REG, 0x78);delay_us(15);
while(TRUE)
{
while(usb_cdc_connected())
{
usb_task();
// Now read back the GAR registers.
gar0 = w5100_read_reg(W5100_GAR0_REG);delay_us(15);
gar1 = w5100_read_reg(W5100_GAR1_REG);delay_us(15);
gar2 = w5100_read_reg(W5100_GAR2_REG);delay_us(15);
gar3 = w5100_read_reg(W5100_GAR3_REG);delay_us(15);
// Send to Serial port monitor
printf(usb_cdc_putc,"Result: %X %X %X %X \n\r", gar0, gar1, gar2, gar3);
delay_ms(2000);
}
} |
|
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Thu Mar 18, 2010 2:40 pm |
|
|
Hmm, looks like my reads are garbled. At one point in my test I did get 12 34 56 78, but I reset and ran again and here's what I got.
Quote: |
Read: 12 34 F0 08
Read: 00 34 F0 02
Read: 00 34 F0 00
Read: 12 04 00 08
Read: 00 04 00 00
Read: 12 04 00 08
Read: 00 34 F0 00
|
But how do I know whether my writes are working 100% as well? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 18, 2010 3:14 pm |
|
|
Try writing all zeros and see what you read back.
See the modifications in bold below:
Quote: |
// See if we can write to the Gateway Address Registers
// (GAR0-GAR3). Just fill them with some test data.
w5100_write_reg(W5100_GAR0_REG, 0x00);delay_us(15);
w5100_write_reg(W5100_GAR1_REG, 0x00);delay_us(15);
w5100_write_reg(W5100_GAR2_REG, 0x00);delay_us(15);
w5100_write_reg(W5100_GAR3_REG, 0x00);delay_us(15);
while(TRUE)
{
while(usb_cdc_connected())
{
usb_task();
// Now read back the GAR registers.
gar0 = w5100_read_reg(W5100_GAR0_REG);delay_us(15);
gar1 = w5100_read_reg(W5100_GAR1_REG);delay_us(15);
gar2 = w5100_read_reg(W5100_GAR2_REG);delay_us(15);
gar3 = w5100_read_reg(W5100_GAR3_REG);delay_us(15);
// Send to Serial port monitor
printf(usb_cdc_putc,"Result: %X %X %X %X \n\r", gar0, gar1, gar2, gar3);
delay_ms(2000);
}
} |
|
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Thu Mar 18, 2010 3:28 pm |
|
|
Strangely enough, this is what I get:
Quote: |
Read: 02 00 02 00
Read: 01 00 01 00
Read: 02 00 02 00
Read: 02 00 02 00
|
|
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Mon Mar 29, 2010 9:56 pm |
|
|
I tried putting 10kohm pullup resistors to SDO and SDI pin to see if it would make any difference but it did not. Then I did spi_write(0x55) and checked the SDO and clock on a scope and they looked perfect. I also tried switching out to a different prototype board but with same results. I still cant figure out what's causing the garbage values.
I'm writing out values 0x12, 0x34, 0x56, 0x78 to the 4 registers before while loop and reading them continuously inside the while loop and this is what I'm getting. My project's going nowhere because this is the most basic step to start with.
Quote: |
Read: 12 04 00 78
Read: 12 34 56 02
Read: 00 02 00 78
Read: 12 02 00 78
Read: 12 34 56 78
Read: 12 04 00 78
Read: 12 34 56 78
Read: 02 00 00 78 |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 30, 2010 1:29 pm |
|
|
Wiznet has a tech forum.
Here is one thread, where he is getting some weird data, similar to you,
and the problem is apparently an incorrect SPI mode:
http://www.wiznet.co.kr/Sub_Modules/en/technical/Q_A_View.asp?boardcd=101&PK_NUM=14652&page=22
I wonder if there is a problem with the hardware SPI module on the
18F4455. You could try using software SPI. I'll test if #use spi()
works OK on vs. 4.066 and post the results. If it does, then you
could use it for software SPI. If not, you could still use bit-bang
routines.
I noticed one other thing. On page 60 of the W5100 data sheet,
it shows a pull-up resistor on the SPI_EN pin. Do you have that
installed ?
http://www.sparkfun.com/datasheets/DevTools/WIZnet/W5100_Datasheet_v1_1_8.pdf
I have another question. I was just re-reading that old thread you linked
to in your first post. Do you have the PIC running at +5v and the
Wiznet running at +3.3v ? Do you have a level converter on the SDO
signal coming from the Wiznet module, which goes to the PIC's SDI pin ? |
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Wed Mar 31, 2010 12:22 pm |
|
|
Spi modes 1 & 3 give no results at all, whereas mode 2 gives me all 00's in result.
The pull up resistor on SPI_EN is already done within the module itself and cant be changed because the board doesnt have an SPI_EN pin.
I do have the PIC running at 5V and Wiznet at 3.3 and yes I am using 74HCT125 between SDO from Wiznet and SDI of PIC.
With regards to #use spi, i tried this simple code. I also used a different compiler version PCH v4.084, 57706.
Code: |
#include <18F4455.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN //needed for USB functionality
#use delay(clock=48000000) //needed for USB functionality
//#use spi (MASTER, MODE=0, DI=PIN_B4, DO=PIN_C6, CLK=PIN_B5, BITS=8, BAUD=100000)
#use spi (MASTER, MODE=0, SPI1, BITS=8, BAUD=100000)
void main()
{
while(TRUE)
{
spi_xfer(0x55);
delay_us(50);
}
} |
On the oscilloscope, I can successfully see 8 clocks and 01010101. I can see the same thing if I use the 'commented' #use spi as well, it's just a bit slower than using the uncommented one.
The other thing is, I can see the same thing on oscope if I use setup_spi() instead of #use spi. So I dont know if this test is so reliable.
Now for the functions that do the actual read and write to Wiznet registers, here's what I have so far but they're not working. I suspect I dont have the reads implemented correctly:
Code: |
void w5100_write_reg(int16 addr, int8 data)
{
output_low(W5100_CS); delay_us(50);
spi_xfer(W5100_WRITE_CMD); delay_us(150);
spi_xfer((addr&0xFF00)>> 8); delay_us(150); // Send address msb
spi_xfer((addr&0x00FF));delay_us(150); // Send address lsb
spi_xfer(data);delay_us(150); // Write data to W5100
output_high(W5100_CS);delay_us(50);
}
int8 w5100_read_reg(int16 addr)
{
int8 retval;
output_low(W5100_CS);delay_us(50);
spi_xfer(W5100_READ_CMD);delay_us(150);
spi_xfer((addr&0xFF00) >> 8); delay_us(150); // Send address msb
spi_xfer((addr&0x00FF));delay_us(150); // Send address lsb
retval = spi_xfer(0);delay_us(150); // Read data from W5100
output_high(W5100_CS);delay_us(50);
return(retval);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 31, 2010 12:41 pm |
|
|
To solve your problem, I would have to buy a Wiznet module from
Sparkfun for $24.95 plus tax and shipping. That's too much for me
to spend to solve your problem. |
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Wed Mar 31, 2010 12:56 pm |
|
|
it's ok. thanks for all your help. but can u tell me if i am doing the read correctly? is spi_xfer(0) the right way to do it? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 31, 2010 1:37 pm |
|
|
I'll show you how to study the problem.
First you make a test program. This is a little program that concentrates
only on the issue that you want to study. In this case, you want to
study the behavior of spi_xfer(), compared to spi_write() and spi_read().
Here is the program:
Code: |
#include <18F4455.h>
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use spi (MASTER, MODE=0, SPI1, BITS=8, BAUD=100000)
//======================================
void main(void)
{
int8 result;
spi_write(0x55);
result = spi_read(0x55);
result = spi_xfer(0x55);
while(1);
}
|
Here's part of the .LST file.
Code: | .................... spi_write(0x55);
003A: MOVF FC9,W
003C: MOVLW 55
003E: MOVWF FC9
0040: RRCF FC7,W
0042: BNC 0040
....................
.................... result = spi_read(0x55);
0044: MOVF FC9,W // Read SSPBUF
0046: MOVLW 55
0048: MOVWF FC9 // Put 0x55 in SSPBUF
004A: RRCF FC7,W // Test BF bit of SSPSTAT
004C: BNC 004A // Wait in loop until BF = 1
004E: MOVFF FC9,06 // Read SSPBUF. Put it in 'result' variable
....................
.................... result = spi_xfer(0x55);
0052: MOVLW 55 // Put 0x55 in 07 loc.
0054: MOVWF 07
0056: MOVLW 08 // Put 0x08 in 08 loc. (not needed)
0058: MOVWF 08
005A: BRA 0004 // Jump to spi_xfer() routine
0004: MOVF FC9,W // Read SSPBUF
0006: MOVFF 07,FC9 // Put 0x55 in SSPBUF
000A: BTFSS FC7.0 // Test BF bit of SSPSTAT
000C: BRA 000A // Wait in loop until BF = 1
000E: MOVFF FC9,01 // Read SSPBUF. Put it in 01 loc.
0012: GOTO 005C (RETURN)
005C: MOVF 01,W // Put 01 loc. in W. (not needed).
005E: MOVFF 01,06 // Put 01 loc. in 'result' variable.
.................... |
This shows that spi_xfer() does basically the same thing as spi_read().
However, it also shows that spi_xfer() has a bug. Here is the Errata
sheet for Rev. A3 silicon for the 18F4455:
http://ww1.microchip.com/downloads/en/DeviceDoc/80220j.pdf
On page 8, it says:
Quote: |
18. Module: MSSP
When the MSSP is configured for SPI mode, the
Buffer Full bit, BF (SSPSTAT<0>), should not be
polled in software to determine when the transfer
is complete.
|
But that's exactly what CCS is doing, as shown in bold below.
That's a bug. This is with vs. 4.084. But I installed vs. 4.106
and they're still doing it. I'll email CCS about this.
Quote: |
0004: MOVF FC9,W // Read SSPBUF
0006: MOVFF 07,FC9 // Put 0x55 in SSPBUF
000A: BTFSS FC7.0 // Test BF bit of SSPSTAT
000C: BRA 000A // Wait in loop until BF = 1
000E: MOVFF FC9,01 // Read SSPBUF. Put it in 01 loc.
0012: GOTO 005C (RETURN)
|
In the spi_write() code, CCS rotates the BF bit into the Carry flag
before testing it. So presumably that's OK and satisfies the errata's
suggestion for a work-around. |
|
|
learner
Joined: 17 Mar 2010 Posts: 10
|
|
Posted: Wed Mar 31, 2010 4:47 pm |
|
|
wow, quite an observation PCM. so does this mean that setup_spi() would work better than #use spi, since spi_xfer has a bug?
I also have an 18F4553 with me but I've never worked with it before. I tried going over the errata sheets before hooking it up but I was pretty overwhelmed with all the MSSP errors it has reported.
So I tried to hook it up anyway but there are couple of problems. I cant use USB with this chip because the compiler says: Quote: | #error Unknown PIC device, USB not supported in this library. |
Then I wanted to use RS232 instead but noticed that RX and SDO use the same pin on the 18f4553. So I guess I cant use this chip at all, because I want to be able to see the results on the hyperterminal and I cant use RS2323 or USB.
Any suggestions?
EDIT: I also have an 18F4550 but it uses the same datasheet and errata as 18F4455 so cant use it either. |
|
|
|
|
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
|