|
|
View previous topic :: View next topic |
Author |
Message |
samikool
Joined: 01 Apr 2021 Posts: 15
|
**SOLVED** SPI data on wire but not being read |
Posted: Wed Apr 07, 2021 1:18 pm |
|
|
Hello guys it's my first time postings so let me know if I miss anything I need to include, but I'm going to try and get every thing in here.
Some background, I'm working with the wiznet 850io, which has a w5500 in it. I got the driver from wiznet, and with a few modifications got it to compile with CCS 5.103.
I then was able to hook it up to a PIC24FJ128GA202 and get it working without issue. All I had to do was set the ip and subnet and then create a socket and the rest was easy.
I'm now trying to port this code over to a PIC24FJ256GA106 and running into issues. After changing all the spi pins to match the new chip, I am seeing the data going out on the wire and coming back from the w5500. However, for some reason, during my spi_reads, I am not reading anything. I will post the code of what I am doing below. There is a good amount but hopefully it is readable enough that I can explain what I'm doing.
First off the config I have is as follows.
Code: |
#ifndef MAIN_H
#define MAIN_H
#include <24FJ256GA106.h>
#device ICSP=1
#use delay(clock=32MHz,crystal=8MHz)
#CASE
#pin_select U1TX=PIN_G8
#pin_select U1RX=PIN_G7
#use rs232(UART1, baud=9600, stream=TP)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#pin_select SCK1OUT=PIN_D4
#pin_select SCK1IN=PIN_D4
#pin_select SDI1=PIN_D5
#pin_select SDO1=PIN_D3
#use spi(MASTER, SPI1, BAUD=2000000, MODE=0, BITS=8, stream=SPI_PORT1)
#endif
|
For my main driver code I basically just try to set the ip and submask try to read it back at the moment. The data and time just lets me know when
the code was compiled, because sometimes it will not properly upload the newly compiled version.
Code: |
void main()
{
delay_ms(1);
printf ("\r\n"
"\r\n"
"\r\n"
"-------------------------------------------------------------------------------\r\n"
""__DATE__" "__TIME__"\r\n"
"-------------------------------------------------------------------------------\r\n"
);
//intended ip
uint8_t ip[4] = {192,168,0,3};
setSIPR(ip);
//intended subnetMask
uint8_t subnetMask[4] = {255,255,255,0};
setSUBR(subnetMask);
//test ip initialized randomly to see what i read back
uint8_t t_ip[4] ={111, 22, 21, 54};
getSIPR(t_ip);
for(int i=0; i<3; i++)
printf("%u.", t_ip[i]);
printf("%u\r\n", t_ip[3]);
while(TRUE);
}
|
Again the weird part about this is that if I watch the wires I will see the IP both go out, and come back, but for some reason it isn't getting read in correctly.
The two functions actually called by the driver to do the writes and reads, I have implemented as follows. the chip select functions I had to implement are called early and I simply out_low or high to the enable pin.
Read:
Code: |
void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {
for(int i=0; i<len; i++){
pBuf[i] = spi_read(0);
}
}
|
Write:
Code: |
void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {
for(int i=0; i<len; i++){
spi_read(pBuf[i]); //use spi read to write so it waits for data to go out.
}
}
|
Again these functions are called by hardcoded functions in the driver, that specify the len and what is in the buffer. The read obviously is supposed to put that data into the buffer but is not in my case. Because even though I see the data come back on the wire physically, it doesn't get read with the spi_read call.
I am really at a loss on this one, any idea's or help would be much appreciated, and please let me know if you need to see any more code or anything that I might have forgotten.
Editing real quick to add a link to what I see on the wire https://imgur.com/a/uhHw4lq
Last edited by samikool on Fri Apr 09, 2021 3:10 pm; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 07, 2021 2:55 pm |
|
|
You're using streams in your #use spi() statement but not with spi_read().
If you only have one #use spi() then it's probably not causing a problem. |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Wed Apr 07, 2021 3:37 pm |
|
|
I do only use it one time, so like you mentioned, from my understanding from browsing the forum I shouldn't need to specify the stream or use the spi_init function. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: SPI data on wire but not being read |
Posted: Wed Apr 07, 2021 7:57 pm |
|
|
samikool wrote: |
I then was able to hook it up to a PIC24FJ128GA202 and get it working without issue.
I'm now trying to port this code over to a PIC24FJ256GA106 and running into issues. |
Compile the program for both PICs and compare the SPI ASM code in the
.LST files. See if there are any important differences. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Wed Apr 07, 2021 11:49 pm |
|
|
Also, generally if you use #use spi, you should use spi_xfer, not spi_read.
Historically these are two separate 'entities'. Originally CCS had functions
for hardware spi only, using spi_setup, spi_read and spi_write.
Then the newer #use spi ability was added (supporting both hardware and
software, and using spi_xfer, spi_transfer_read, spi_transfer_write.
If you look in the manual starting with #use spi, you will see the 'references'
at the bottom of the entry do not mention spi_read or spi_write. Similarly
if you start with setup_spi, this only mentions spi_read & spi_write, not
spi_xfer.
Generally, it is very dangerous to mix the two forms. A lot of the time the
stuff will not work properly if you do.
So make a decision. If you want to use spi_read and spi_write, change
your setup, get rid of #use spi, and use spi_setup. Otherwise, keep the
#use, and change to using spi_xfer, spi_transfer_read and
spi_transfer_write.
The drivers on some chips are more 'lenient' about mixing than on others,
so it may simply be that your original working one was one that accepted
this and the new one is not.
Then #use supports sending more than a byte in a transfer. So, either
add BITS=8 to your #use, or make the value you send into an int8.
You use '0' as a dummy value, but this in PCD, is an int16. So use an
explicit cast to make this an int8: "(unsigned int8)0". Otherwise by default
it will be performing 16bit transfers.
Also, 'double check' you have the DI and DO selections right. Remember
DO on the slave device goes to DI on the PIC and vice versa. It could
simply be you have got these reversed.
Also as one more comment make sure you have a line at the start of the
code to disable the parallel master port. The pins you are using are PMP
pins, and though CCS disables most peripherals automatically, I have
occasionally seen the PMP cause issues. |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Thu Apr 08, 2021 8:02 am |
|
|
Thanks for the advice guys, I will work on both of these today and post my results. |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Thu Apr 08, 2021 10:59 am |
|
|
Okay guys I have a lead as to what I think is happenening, and hopefully someone can make sense of this. I switched over to using the spi_transfer_read/write functions, and they now look like this. I believe I am doing them correctly, but am just posting them so you guys know what has changed.
Code: |
void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {
spi_transfer_read(SPI_PORT1, pBuf, (int16) len);
}
|
Code: |
void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {
spi_transfer_write(SPI_PORT1, pBuf,(int16) len);
}
|
spi init:
Code: | #use spi(MASTER, FORCE_HW, SPI1, BAUD=1000000, MODE=0, BITS=8, stream=SPI_PORT1) |
My main code now looks like this:
Code: |
void main()
{
PMPEN = 0;
//delay_us(500); //time needed for
//intended ip
uint8_t ip[4] = {192,168,0,3};
setSIPR(ip);
//intended subnetMask
uint8_t subnetMask[4] = {255,255,255,0};
setSUBR(subnetMask);
uint8_t srv_ip[4] = {192, 168, 0, 2};
uint16_t srv_port = 34000;
int8_t sn = socket(0, Sn_MR_TCP, 6000, 0x00);
if(sn >= 0){
//test ip initialized randomly to see what i read back
uint8_t t_ip[4] ={111, 22, 21, 54};
getSIPR(t_ip);
// printf("success\r\n");
// for(int i=0; i<3; i++)
// printf("%u.", t_ip[i]);
// printf("%u\r\n", t_ip[3]);
// delay_ms(1000);
// int m = getSn_MR(sn);
// delay_us(200);
// delay_ms(1);
// printf("mode: %d\r\n", m);
//
// delay_ms(1000);
//
int8_t s = connect(sn, srv_ip, srv_port);
delay_us(500);
if(s >= 0)
printf("success c\r\n");
else
printf("connection failure...%d\r\n", s);
}
}
|
So one difference you'll notice immediately is that I'm not printing the date/time anymore what I found is that the delay from printing was causing me to not read the correct IP on the SPI line. Additionally I was never and still can't read the IP correctly immediately after programming the PIC board, but on power cycling can read it perfectly every time (with no prints). On further investigation I am noticing that the baud-rate on the SPI line is actually changing mid execution every time as I run this program. An example of that is shown here: https://imgur.com/a/MngDRJK . At times this will happen mid transfer like on the picture shown, other times it will happen between transfers but it does happen every time. It seems at the changed baud rate, I can not read the data coming in. Additionally whatever I set the baud-rate to in my #use seems to be the "new" speed. The original transfer rate is always 4x less, but works.
I don't have a ton of experience with SPI but this seems like it couldn't work? If it is this can work like this I'm sort of back to square one and the next step would be to look at the ASM code more thoroughly like you suggested. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 08, 2021 1:26 pm |
|
|
4x sounds like it's the PLL.
You could poll the PLL Lock Status bit, or you could put a delay_ms(100);
statement at the start of main(). |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Apr 09, 2021 12:49 am |
|
|
The 'S' in SPI, stands for synchronous. The port send it's own clock, so
provided your slave device supports the rate being sent, it should work
whatever the speed being sent actually 'is'. As PCM says, 4*, sounds like a
PLL issue. Generally, quite a lot of the time with PIC's, you do need to
delay at the start, since they do wake up very quickly compared to other
chips. I notice the 5500 chip says it needs 1mSec after boot before
it can accept data. When the boot actually occurs as far as the chip is
concerned depends on how the RST line is wired. The reference schematic
does not show any actual connection to this, and the data sheet does not
say how quickly the chip will generate this internally.
Now it is odd that it is the first slower transactions that work. Have you got
an oscilloscope?. If you can measure whether the early clock speed or
the later speed is the one you are actually specifying, it may give a clue
to what is going on. One thought is a lot of the PIC24's do not generate
quite enough loading to correctly start many crystals. I'd actually wonder
if it is waking using the fail safe, and starting on the internal 8MHz clock
and then after a period the external oscillator is starting, and the chip
switches to this with the PLL. Now looking at your code, there is one
glaring thing. You do not have the NOIESO fuse set. This means the chip
will boot as fast as it possibly can on the internal oscillator, and then will
switch to your crystal with the PLL, once this has started and it stable.
Result a significant period running at the wrong clock rate....
So add the fuse NOIESO.
Thinking about the Wiznet chip, this is a processor, so it may simply
be that this does not like/support the SPI rate 'changing' after the first
transaction, so this may be what is causing the issue.
You will find the PIC boots slightly slower, but hopefully will then find
it runs at one speed.
If then the transactions don't work, it would probably imply that there
is something about the connection that is preventing 1MHz from working.
Too much capacitance or something similar....
Not being able to read after programming is normal on a lot of devices.
Problem is that programming resets the PIC, but does not reset the other
devices being talked to. Result chaos.... |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Fri Apr 09, 2021 7:28 am |
|
|
Again thanks for the advice guys! I will be back at it again today, and update later.
I forgot to add in response to your question Ttelmah, it is the lower clock speed that's working. I think in one of the posts above I have a picture if you're curious to take a look.
Essentially I'm creating a socket to try and connect to a Python server running on my computer, and once it stops being able to read the SPI transactions the driver fails. At the moment I'm getting stuck in the connect function at the very end where it's asking for the status of the socket, and I see the SOCK_OK response on the SPI wire with my oscilloscope, but the PIC fails to read it at that point (because the baud changed) and then no connection is made. |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Fri Apr 09, 2021 7:59 am |
|
|
Quick update after adding the fuse you suggested it did seem to makes things more consistent. I now can get the correct baud-rate without putting a random delay at the start of my main. Additionally it now reads the correct data at the correct baud-rate for a time, but still stops working later on as I mentioned before (just without the baud-rate changing). This leads me to think the issue was not with the changing baud-rate, but rather something else is happening that is stopping the transactions from being properly read.
Adding and edit here to show the code I'm currently running.
I will keep investigating.
main.h:
Code: |
#ifndef MAIN_H
#define MAIN_H
#include <24FJ256GA106.h>
#device ICSP=1
#use delay(clock=32MHz,crystal=8MHz)
#WORD PMCON = getenv("PMCON")
#bit PMPEN = PMCON.15
#CASE
#pin_select U1TX=PIN_G8
#pin_select U1RX=PIN_G7
#use rs232(UART1, baud=9600, stream=TP)
#define DEBUG_PRINTF printf
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#FUSES NOIESO
#pin_select SCK1OUT=PIN_D4
#pin_select SCK1IN=PIN_D4
#pin_select SDI1=PIN_D5
#pin_select SDO1=PIN_D3 //SPI1
#use spi(MASTER, FORCE_HW, SPI1, BAUD=2000000, MODE=0, BITS=8, stream=SPI_PORT1)
#endif
|
main.c:
Code: |
#include "main.h"
#include "wizchip_conf.h"
#include "wizchip_conf.c"
#include <wiznet.c>
void main()
{
PMPEN = 0;
//intended ip
uint8_t ip[4] = {192,168,0,3};
setSIPR(ip);
int wrong_count = 0;
int run_count = 1;
spi_init(SPI_PORT1, TRUE);
delay_ms(5000); //!!! important delay !!!
// while(sn >= 0)
while(TRUE)
{
uint8_t t_ip[4] ={111, 22, 21, 54};
getSIPR(t_ip);
if(t_ip[0] == 0 || t_ip[0] == 111)
wrong_count++;
for(int i=0; i<3; i++)
printf("%u.", t_ip[i]);
printf("%u\r\n", t_ip[3]);
printf("%d/%d\r\n", wrong_count, run_count);
delay_ms(10);
run_count++;
delay_ms(500);
}
}
|
So essentially I write the IP and then read it over and over again. The result is that on the first read I read correctly. On every subsequent read, I read all 0s and fail to read the IP correctly. The entire time I watch the SPI lines and the data/clocks/baud-rate looks perfect as shown here: https://imgur.com/a/h3DqgX5. This is leading me to believe that this is timing related somehow. After a certain amount of time, even though the data on the lines is perfect, my chip fails to read it. By adding a large delay at the start of main, every read will fail.
I will be testing other chips soon, so I can test if it's a chip fault. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Apr 09, 2021 11:21 am |
|
|
You don't show the commands you use to setup these transfers.
To send the IP, would require you to send the register address it is to go
to, followed by a control byte with OM=11 (for a four byte transfer),
followed by the four bytes. You only show the code sending the four bytes.
Not the routines that set this up.
Honestly SPI transfers are much more reliable if you control the CS line
otherwise if even a single bit is missed, the whole transfer will get out of
sync and not recover. With CS you can always restart the frame. |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Fri Apr 09, 2021 2:10 pm |
|
|
Sorry yes a lot of this stuff is hidden or tucked away in the driver. I do "control" the cs line by specifying the pin it is connected to on the board. Then the driver actually contains the hardcoded functions that set all the transfers up. I just had to fill out 4 functions which I'll list below, and then the driver uses them to talk to the w5500. I will link the driver I used and ported over to ccs c. https://github.com/Wiznet/ioLibrary_Driver.
Code: |
void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {
spi_transfer_read(SPI_PORT1, pBuf, (int16) len);
}
void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {
spi_transfer_write(SPI_PORT1, pBuf, (int16) len);
}
void wizchip_cs_select(void) {
output_low(PIN_F5);
}
void wizchip_cs_deselect(void) {
output_high(PIN_F5);
}
|
The weird part is that those transfers work at first. When I start the chip I can watch the transfers on the line and look at the datasheet and see it is behaving as intended. If the code manages to get far enough before being unable to read from the SPI line, I can and even use Wireshark to see the connection being made to my simple python server. However, at a certain point (less than 1 second) my PIC chip seems to just lose the ability to read the SPI line. It will read all 0s even though I can see the transfer on the SPI line is correct and non-zero. |
|
|
samikool
Joined: 01 Apr 2021 Posts: 15
|
|
Posted: Fri Apr 09, 2021 3:09 pm |
|
|
Alright guys I have solved the issue, and its a funny fix in hindsight.
I didn't mention because I didn't think it would be totally relevant but there are several SPI devices on the bus. In the course of solving the problem, I branched from the original project into a isolated one where I was only talking to the Wiznet. Of course those devices don't magically disappear from the board, so in the process of doing that, I removed all the code that set their CS pins high. I moved that code over so their lines were no longer floating and everything works perfectly as intended.
Thanks for all the help and ideas debugging. I'm not sure how to do it since I'm new to these forums, but we can mark the thread as solved now. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sat Apr 10, 2021 12:42 am |
|
|
Official 'Aaaargh!'....
You understood from my question that I was starting to think something
had to be going wrong with the transfers. I'm glad you are controlling the
CS. This makes SPI so much better. That there were other devices that
were 'floating on', is a real nasty,
Anyway glad you have it working now. |
|
|
|
|
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
|