|
|
View previous topic :: View next topic |
Author |
Message |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
Slave SPI |
Posted: Tue Jul 27, 2021 1:00 pm |
|
|
PIC18F23K22
CCS 5.094
MPLAB 8.92
Connecting two PIC18F23K22 pics together via SPI1.
I get no data out of the SLAVE side. Master side is clocking, doing to slave_select correctly.
I just did the following simple loop on the Slave:
Code: | while(1) { // endless main loop
delay_ms(5);
spi_write(0x25);
output_toggle(PIN_A0);
} // end endless loop
|
to force the SLAVE to just constantly send. The code hangs at the spi_write() function. I know this because PIN_A0 does not toggle. When I comment out the spi_write(), PIN_A0 toggles.
I am not using the default Slave_Select, I am using PIN_C2. It is controlled by the MASTER via output_high() and output_low()
SLAVE is set up as:
Code: | setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_SS_DISABLED | spi_clk_div_16 | spi_xmit_l_to_h); |
Not sure what is going on here, I thought I could force the slave to send on the spi by continuously calling spi_write.
The SCLK is supplied by the MASTER via a spi_read(0); call, and the SCLK is present verified with the scope.
I can post more code if needed, just tried to whittle it down the a bare minimum to see why the SLAVE will not send. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Jul 27, 2021 2:14 pm |
|
|
Expanding on this topic a bit, it seems to be a timing problem with using the manual slave select line. I can get the fixed data sent by the slave to the master, but I have to wait several ms to do so. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Jul 27, 2021 2:30 pm |
|
|
Well a closer look shows the master is only reading back what it wrote in the following line: Code: | depth = spi_read(0x01); |
so my read back is 1 instead of what the slave should write out which is
The slave is not hanging on the spi_write call, but DO shows no data. I do see data on DI to the slave which is DO of the Master. SCLK is correct too.
seems like something fundamental and simple but not seeing it. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Jul 27, 2021 6:25 pm |
|
|
Not sure what is going on or how much to try to explain.
Basically it works now between the two pics.
Except for certain conditions like
a decimal 33 sent from the slave to the master shows up as a 32
A 0X31 shows up at the Master as 48 decimal.
A 0x0FF shows up at the master as 255 decimal
Mode 0 does not work at all only reports 0.
I am running mode 1 now.
Master is set up like this:
Code: | #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)
output_high(LED1_CNTRL); // This is the Slave Select l
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_SS_DISABLED | spi_clk_div_16); // Use manual line instead of SS line on PIC for control
|
main loop is
Code: | output_low(LED1_CNTRL);
delay_us(100);
depth = spi_read(0x00);
delay_us(10);
fprintf(HOST_SERIAL, "D= %u\n\r",depth);
output_high(LED1_CNTRL);
|
SLAVE:
Code: | #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)
#DEFINE SLAVE_SELECTOR PIN_C2
setup_spi(SPI_SLAVE | SPI_MODE_1 | SPI_SS_DISABLED | spi_clk_div_16);
|
main loop:
Code: | while(1) { // endless main loop
if(!input(SLAVE_SELECTOR)) {
spi_write(33);
output_toggle(PIN_A0);
}
} // end endless loop
|
hopefully someone can explain this behavior. After a 14 hr day, I am done, will answer questions tomorrow.
thank you all for your advice and time in advance. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Wed Jul 28, 2021 12:01 am |
|
|
The behaviour you are seeing, says that you have a physical problem with
the connections. The clock is being delayed. How long are the wires?. How
fast is the /16 clock (depends on your PIC clock rate). What sort of wire
is being used?. Do you have any termination on the signals?. Wires are
'transmission lines', as such signals will 'ring' if the lines are not terminated
to match the impedance of the wire. It sounds as if the rising edge in
particular is being delayed. There are problems worst on the clock line, but
on the SDI line as well, which is why some edges are not correctly received.
How are the grounds connected between the chips?. What voltage is the
system running?.
You can reduce ringing, by just adding perhaps a 22R resistor into each
signal line at it's 'source'. This fractionally reduces the actual clock edge
speed being sent on the line, thereby massively reducing ringing. Even if
the bus is running very slowly, the edges are those produced by the PIC
gates 'flat out', so ringing will occur. It is just that at low speeds this
will generally die away before the sample point of the signal. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Jul 28, 2021 4:43 am |
|
|
The 2 examples you post, lose the last bit, 'classic' for a long serial line with RC clocks. BTDT decades ago. Could get 12-13 miles on the serial loops, never got 15 until I slowed the clock down.
As Mr. T points out there's a few 'hardware' issues that can cause the loss of data but I'll add...
PIC clock... should be real xtal/2 caps not internal RC
distance...you need GOOD copper between PICs
clock.. what speed ? there's a speed vs distance demon |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Wed Jul 28, 2021 9:45 am |
|
|
Thanks for the responses. It is a moving target problem, changing one thing makes it either work or not work. Changing back may or may not make it work again.
So, layout, ringing sounds on target.
Vcc is 3.3V
Grounds between pics are connected via a ground plane on the top of the PCB, these chips are surface mount.
Crystal is 16MHz clock speed is 64Mhz
no termination resistors or pull ups or pull downs.
chip distances is about 2 inches. Lines do have a couple vias on them as well and are two ounce copper and are 0.010" in width.
I will try the series resistors to settle the ringing.
Also may set the clock speed to be 16MHz to slow things down as well. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Wed Jul 28, 2021 10:21 am |
|
|
changed my clock statements on both pics to be crystal 16M and clock 16M instead of clock 64M
put a DIV-64 on the SPI clock on both pics.
still do not have good data, looked close with a scope and I have 250mV overshoot on the rising edges of the SCLK signal and a -250mV undershoot (below ground) on the falling edges of the SCLK signal.
I will try some series resistances next.
Hopefully a board or communication scheme is not needed.
I usually use USE SPI to do my SPI setup but in this case used SETUP_SPI because I could not get USE SPI to compile when doing MASTER and SLAVE calls.
would that be a better way so I could drop the communication speeds really low? may not be helpful as the I/O change really fast to different states. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Wed Jul 28, 2021 10:38 am |
|
|
Your issue with mode 0, is in the errata. The chip has a problem as a
master when reading data back that it will assert the BF bit to say it
has data immediately, when CKE is zero.
Big caveat....
Really at your slow clock rate, it should be fine, especially with such small
lengths involved. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Wed Jul 28, 2021 11:25 am |
|
|
Ttelmah I agree on the data rates should work, I go about the same distance and much faster with SPI on the same board. I tried the other SPI modes and no improvement.
last effort will be series resistors. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Wed Jul 28, 2021 1:27 pm |
|
|
Unless someone has some insight, I am tapping out and designing this portion out. Resistors made no difference. Does not make sense, SPI running all over this board, just not this one. I hate the redesign, but I really do not want to support something that is obviously picky in this configuration for some reason. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Thu Jul 29, 2021 1:16 am |
|
|
There are a number of things that might be causing your issues.
Are you setting up the slew rate control for the pins?. Must admit I'd be
surprised to see overshoot if this is enabled.
Try adding set_slow_slew_c(FALSE); and the same for all the ports you
are using. I'm assuming you are using the default port C pins for the SPI.
Given your slow clock rate, you can then try with this enabled. If the problem
disappears you know it is a transmission line problem.
Generally the newer generation chips like this that support lower voltage
operation, become increasingly sensitive to their supply. How well decoupled
are the chips?. Really good ceramic capacitors close to the supply legs on
both?. Anything else on the board that might be generating noise?. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Thu Jul 29, 2021 4:42 pm |
|
|
OK, burned another day on SPI between two pics,
broke camp on using spi_read and spi_write.
did code for using SPI_XFER and #USE SPI()
what is happening now is, I get all 1s sent. My signals, i.e. clock looks great no ringing or overshooting. Still is not working though. Here is my code snippets.
MASTER:
Code: |
#DEFINE CS_7766 PIN_A5
#INCLUDE <18F23K22.h>
#use SPI(master, bits=8, mode=0, clk=PIN_C3, DO=PIN_C5, DI=PIN_C4, enable=PIN_A0, sample_rise, enable_active=1, baud=100000, stream=STREAM_7766)
|
Code: |
void main()
{
output_low(CS_7766);
delay_ms(1000);
spi_init(STREAM_7766,100000);
while (1) {
output_HIGH(CS_7766);
disable_interrupts(global);
delay_us(100);
depth = spi_xfer(STREAM_7766, 0);
output_low(CS_7766);
enable_interrupts(global);
output_low(CS_7766);
} // end while
} // end main
|
SLAVE:
Code: |
#DEFINE SLAVE_SELECTOR PIN_A5
#use spi(slave, bits=8, mode=0, CLK=PIN_C3, DO=PIN_C5, DI=PIN_C4, enable=PIN_A5, sample_rise, STREAM=DEPTH_1)
#INT_SSP
void ssp_isr(void) {
spi_xfer(DEPTH_1,0x01,8);
}
spi_init(DEPTH_1,100000);
void main() {
while(1) { // endless main loop
delay_us(1);
}
|
The interrupt in the slave was a late attempt, I just get all 1,s now.
if I do force_sw in the # use spi it runs really slow and seems to only send one bit per each read by the master.
comments and ideas are welcome. Seems like it is close. But after another long day, what do I know? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Fri Jul 30, 2021 12:50 am |
|
|
Suite of things:
A slave does not have a speed. Get rid of the SPI_init on the slave.
Setting this can result in invalid chip configurations.
Use the port names. Much easier. You seem to be using a high select
line. Why?. If you want to use the slave select, this has to be low for
a transfer, and should only be low for the actual transfer. This is why it is
marked /SS. Low slave select. You talks about using software SPI. You do
understand this can _only_ apply to the master?.
Setting a slow baud rate does not force software to be used, since the
compiler can set this up using timer2. Understand that on an SPI transfer,
you always receive the byte loaded 'last time' by the slave. Loading this
is what 'spi_prewrite' is for, or load it with the read on the slave:
Code: |
//In the master
#use SPI(master, bits=8, mode=0, SPI1, enable=PIN_A0, enable_active=0, baud=100000, stream=STREAM_7766)
//Enable must be active low.
//Then in slave.
#use spi(slave, bits=8, mode=0, SPI1, STREAM=DEPTH_1, ENABLE=PIN_A5, ENABLE_ACTIVE=0)
//the mode already specifies the sample edge etc...
//slave select, will _only_ work in the slave if the enable is set
//to the SS pin, and ENABLE_ACTIVE is 0. It physically cannot work
//with any other configuration.
#INT_SSP
void ssp_isr(void)
{
int8 dummy;
dummy=spi_xfer(DEPTH_1,0x01);
//This receives the byte transferred by the master, and loads the
//byte to return for the next transfer. Since you are specifying
//bits=8, a word length is not needed.
}
void main()
{
//Er what you posted cannot work, since the interrupt is not enabled
spi_prewrite(DEPTH_1,1); //preload the first byte
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(TRUE)
delay_us(1);
}
|
Understand that every transfer both sends and receives. The master sends
a dummy byte (in your case 0, and clocks a byte back. The slave receives
this byte, and loads the _next_ byte to transfer |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
|
|
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
|