|
|
View previous topic :: View next topic |
Author |
Message |
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
PIC18LF8723 hanging during spi_write |
Posted: Fri Mar 03, 2017 3:43 pm |
|
|
Hello everyone,
I am having a weird problem that according to this forum "shouldn't exist", but it does. My issue is with the hardware SPI2 port.
Here are the pertinent portions of the setup code:
Code: |
setup_oscillator(OSC_16MHZ|OSC_INTRC); // Setup the internal oscillator
disable_interrupts(INT_SSP2); // Make sure that the SSP2 port interrupt is turned off
// Since we are about to start talking to the thermocouple ADCs, let's set up the SPI2 port for business
setup_spi2(SPI_MASTER | SPI_SCK_IDLE_LOW | SPI_CLK_DIV_64); // Make SPI2 the master of the board
|
Here is the routine that I wrote to write the configuration registers to the unit. Note that I put some test code at the end to read it back:
Code: |
void WriteBothADC_Config (void)
{
// Get ready to write to two ADCs at the same time...since we are only writing and not reading
int8 SPI_Temp; // Register used to hold the temporary SPI in/out as needed
output_low(TC_CS1); // Make the chip select lines low for the first two ADCs
output_low(TC_CS2);
SPI_Temp = (TCADC_Config0_Address | TCADC_WriteMask); // Make the SPI Temp register equal to the Configuration 0 address ORed with the write mask
spi_write2(SPI_Temp); // Send that we want to start writing with the zero configuration register over to the ADC
SPI_Temp = TCADC_Cfg0_Reg; // Load the lower config register with our default
spi_write2(SPI_Temp); // Send the first configuration register over to the ADCs
SPI_Temp = TCADC_Cfg1_Re; // Load the upper config register with our default
spi_write2(SPI_Temp); // Send the second configuration register over to the ADCs (Note that this is the second write of a multi-byte write)
output_high(TC_CS1); // Make both of the chip selects high again
output_high(TC_CS2);
output_low(TC_CS1); // Make the chip select low so that we can read the result
SPI_Temp = TCADC_Config0_Address; // Make the SPI_Temp equal to the address of the data register in the ADC and don't mask it with the write bit since we want to read the ADC
spi_write2(SPI_Temp); // Send that we want to start reading the data registers over to the ADC
SPI_Temp = spi_read2(0); // Read the MSByte of the result and save it in the shift register
SPI_Temp = spi_read2(0); // **Duplicate for testing**
output_high(TC_CS1); // Return the chip select high so that we can look at something else
output_high(TC_CS1); //**Duplicate (Place for trigger)
// Return the chip select high so that we can look at something else
return; // Return since we are done
}
|
The system will hang up on the spi_read statement. What happens, if I read two registers, it will always hang on the second transaction if I use only spi_read(), but if I replace the read-only with a bi-directional transaction of spi_read(0); it will hang on the first statement. Looking at the scope, all write transactions appear to be going through without a hitch. On the read, I can send the MAX31856 the address byte, but it won't generate the clock to read the register in either scenario. Here is the part of the list file that it loses its mind on:
Code: | .................... SPI_Temp = spi_read2(0); // Read the MSByte of the result and save it in the shift register
001FA: MOVF F66,W
001FC: CLRF F66
001FE: RRCF F64,W
00200: BNC 01FE
00202: MOVFF F66,3E |
It gets stuck on 001FE and 0020. It is looking at the Buffer Full bit of the SSPCON2_Stat register. The bit is never getting set because the clocks are never generated, so it sits there waiting forever. Unusual is it that if I try to output a 0 with the read, it get latched on the first statement, but otherwise it will get lost on the second read. The fact that neither of them generate a clock would make you think that it should always hang on the first one.
Looking at the rest of the SFRs during this anomaly, the BufferFull bit(SSP2STAT.0) is set after the write operation. When I do a read, the clocks never get sent. The Write Collision bit gets set on the second failed transaction when spi_read(); is used and it is set on the first write when spi_read(0) is used.
I guess the question is, why is the BufferFull bit staying set after a Master Write operation?
I am about ready to give up on the hardware SPI module on this one and try the USE_SPI# for software support. I have total control of the I/O on this chip, so I am sure I can just bit-bang the thing entirely...but I would like to know why this is occurring. I hope that my doing this deep of an investigation will help us either nail it, or write it off to the errata.
I am using compiler Version 5.055. Let me know if you need any more information to make an assessment or tell me to forget it and "bang" my way through it. Thanks! _________________ Life is too short to only write code in assembly... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Fri Mar 03, 2017 3:56 pm |
|
|
dumb question(?) but if you cut IDENTICAL code for the 1st SPI port, does it work ?
If so, I'd dump out that listing as well and compare line by line as they _should_ be the same,except for SPI port registers( I'm assuming the bits are the same......)
just thinking out loud here.....
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 03, 2017 5:32 pm |
|
|
You have this mode selection:
Quote: |
setup_spi2(SPI_MASTER | SPI_SCK_IDLE_LOW | SPI_CLK_DIV_64);
|
The PIC's .h file has this:
Quote: |
#define SPI_L_TO_H SPI_SCK_IDLE_LOW
#define SPI_H_TO_L SPI_SCK_IDLE_HIGH
|
Which means you are using SPI Mode 1, based on the following table:
Code: | // SPI mode definitions (for 16F and 18F PICs).
#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) |
The diagram on this website shows that in Mode 1, SCK idles low
and samples on the falling edge.
http://www.totalphase.com/support/articles/200349236-SPI-Background#modes
The Maxim datasheet shows on page 6 that they are using Mode 3.
https://datasheets.maximintegrated.com/en/ds/MAX31856.pdf
There is a note that says SCLK can be either polarity. But in my estimate
this means it must still sample on the rising edge, which means it can use
Mode 3 or Mode 0. But not Mode 1.
So I suggest that you add those four #define statements for the SPI mode
above main(), and change your setup_spi2() statement as shown below:
Quote: |
setup_spi2(SPI_MASTER | SPI_MODE_3 | SPI_CLK_DIV_64); |
|
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Fri Mar 03, 2017 5:52 pm |
|
|
Thanks for the thought, Jay. I appreciate any fresh ideas at this point. That is something that I can't try on the current hardware easily. I can build it and look at the List and see if there was any difference.
I've been pouring over the datasheet and am wondering if I should try to "force" a dummy read of the SSP2BUF register after each read/write in hopes to clear the Buffer Full flag before I initiate the next command. What would be the best way to test that...using the #byte pre-processor command?
Any guidance is appreciated. _________________ Life is too short to only write code in assembly... |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Fri Mar 03, 2017 6:18 pm |
|
|
You nailed it PCM!!! I must say that I am very surprised that such a configuration would completely "hose" the communication. I would expect gibberish before no clock.
I got an assembly error with using SPI_Mode_3 within the setup_spi2 statement. I "forced it in, and found that I still had to invert the sense of the SPI_XMIT option, and it worked. Here is the complete statement:
Code: | setup_spi2(SPI_MASTER | (SPI_SCK_IDLE_HIGH | SPI_XMIT_H_TO_L) | SPI_CLK_DIV_64); |
Again, this worked, and I sincerely appreciate your input. I hope that someone else can benefit from this post as I have been reading the forum for the last two days and didn't find this exact problem.
Thanks again, and have an awesome weekend!! _________________ Life is too short to only write code in assembly... |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Fri Mar 03, 2017 6:27 pm |
|
|
It turns out that when inverting the sense it works too. Here is the statement:
Code: | setup_spi2(SPI_MASTER | (SPI_SCK_IDLE_LOW | SPI_XMIT_L_TO_H) | SPI_CLK_DIV_64); |
Thanks again for your help _________________ Life is too short to only write code in assembly... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19541
|
|
Posted: Sat Mar 04, 2017 2:16 am |
|
|
It is an interesting behaviour.
Have to agree, it "shouldn't happen". Whatever clock edge you set or read on, the master should always be able to complete the transaction.
That setting things up right, fixes it, is good news, and obviously solves this for now.
However I suspect you may well have found an undocumented 'errata' with the chip. There are a couple of others in the family, where there is an erratum on the SPI, which could cause the hang behaviour. |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Sat Mar 04, 2017 2:51 am |
|
|
Thank you for your reply, Ttelmah.
You were one of the more out-spoken people on the anticipated behavior of this port over the years and I feel a bit vindicated that you think that it may be an errata issue as well. Most of the errata for this particular chip deal with the MSSP port, but not this behavior. It is a weird one indeed.
I am grateful that once-again, you all on the CCS Forum were able to get me "over the hump" on what seemed to be an insurmountable problem. Though I could have "bullied" through this one, I am glad to be able to use the hardware functions.
Thanks again everyone. A prosperous 2017 to you all!! _________________ Life is too short to only write code in assembly... |
|
|
|
|
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
|