|
|
View previous topic :: View next topic |
Author |
Message |
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
5.102: spi_init() can generate different code |
Posted: Tue Feb 16, 2021 1:57 pm |
|
|
This has been reported to CCS, but I am posting this here in case anyone else stumbles on it.
I am bringing up a new board based on 24FJ256GA106. It uses about a dozen SPI devices, and I noticed some of my code was not emitting SPI data like it should, but the exact code (copy/paste) in other spots of the code worked fine.
It was as if a spi_xfer() worked great in one spot, and failed to work in another. Based on the location of the code, there is a SPI1CON1 configuration that was setting the wrong value:
Code: |
.............................. spi_init (SPI_MODE0, TRUE);
01204 A9E241 BCLR.B 241.7 : SPI1STAT.SPIEN = 0
01206 A9C240 BCLR.B 240.6 : SPI1STAT.SPIROV = 0
01208 201204 MOV #120,W4 : W4 = 120
0120A 881214 MOV W4,242 : SPI1CON1 = W4
0120C A8E241 BSET.B 241.7 : SPI1STAT.SPIEN = 1
|
versus
Code: |
.............................. spi_init (SPI_MODE0, TRUE);
*
008C2 A9E241 BCLR.B 241.7 : SPI1STAT.SPIEN = 0
008C4 A9C240 BCLR.B 240.6 : SPI1STAT.SPIROV = 0
008C6 2013F4 MOV #13F,W4 : W4 = 13F
008C8 881214 MOV W4,242 : SPI1CON1 = W4
008CA A8E241 BSET.B 241.7 : SPI1STAT.SPIEN = 1
|
Above, you can see that the same line of source produced a different value to go into W4 (120 versus 13F).
Beyond moving code around until it works, I have not found a workaround. I'll update this thread with more info when it is figured out. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Last edited by allenhuffman on Wed Feb 17, 2021 8:40 am; edited 1 time in total |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Tue Feb 16, 2021 2:21 pm |
|
|
I came up with a workaround I am using until this gets resolved. I just looked at the generated assembly code, and did it manually in the spots where the compiler was making incorrect code:
Code: |
#word SPI1STAT = getenv("SFR:SPI1STAT")
#bit SPIEN = SPI1STAT.15 // bit 15 - SPIEN
#bit SPIROV = SPI1STAT.6 // bit 6 - SPIROV
#word SPI1CON1 = getenv("SFR:SPI1CON1")
void DAC8534Write (unsigned int SlaveSelectPin, unsigned int CommandByte,
unsigned int Value)
{
//spi_init (SPI_MODE0, TRUE);
//SPI1STAT.SPIEN = 0
SPIEN = 0;
//SPI1STAT.SPIROV = 0
SPIROV = 0;
//0120C 201204 MOV #120,W4 : W4 = 120
SPI1CON1 = 0x120;
//SPI1STAT.SPIEN = 1;
SPIEN = 1;
...
|
Now it works. I may have to write my own wrapper functions for these and just use it, since moving code around can cause working code to break. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Feb 17, 2021 1:40 am |
|
|
This situation could occur if you have multiple #use spi() statements in
your program and are not using streams. The last #use spi() line that
the compiler encounters will be "in effect" for code that comes after it
linearly in the source file.
Or, you could be using streams in the #use spi() statements, but not
specifying the stream in spi_init() statements, or occasionally forgetting
to specify the stream. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Feb 17, 2021 2:13 am |
|
|
I'm actually worried here by his stream name.
He is using SPI_MODE0, as the stream name here. I presume he has
two #use SPI statements setup, one with SPI_MODE0, and another
with another mode. Now, I use SPI mode switching like this, but have
always made the stream name less likely to accidentally clash, so
DISPLAY_SPIMODE0
MEMORY_SPIMODE3
I've also always disabled the existing port selection before reselecting:
Code: |
spi_init(DISPLAY_SPIMODE0,FALSE);
spi_init(MEMORY_SPIMODE3,TRUE);
|
I've never seen a selection issue working like this.
I also wonder on the '5.10' here. Is this his CCS version number?. If so,
upgrade. 5.10, was a 'beta' at best. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 17, 2021 7:54 am |
|
|
Four streams. SPI and SPI2, mode 0 and mode 1. Might be more since I think one of the devices might use mode 3. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 17, 2021 8:44 am |
|
|
Ttelmah wrote: | I also wonder on the '5.10' here. Is this his CCS version number?. If so,
upgrade. 5.10, was a 'beta' at best. |
5.102, actually (subject edited). Any time I run in to something that looks like a compiler issue, I always make sure I am running the latest release to validate before reporting it.
CCS has my code and is looking in to it.
Things seem to be working fine on our legacy projects that use only one SPI bus and only a few devices that swap between Mode 0 and Mode 1. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 17, 2021 8:55 am |
|
|
I will add that, since this is a new project, I have taken the advice given repeatedly here about not using Multiple Compilation Units. I also created the initial project with the PIC24 Wizard.
...and immediately found a bug in the Wizard. CCS already sent me an updated .exe that is supposed to resolve it.
A note about my code. Currently, it's just a Console (print a menu, input a command) that then jumps into routines that either read or write to SPI devices. I am writing a simple test app for validating this new hardware.
Every device is in its own .c file. Moving them around seems to change how code is generated. We've previously ran into issues with functions being past some memory address creating different code that revealed a bug with int8s potentially being corrupted by ISRs. Maybe this is just another one of those. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Feb 17, 2021 9:07 am |
|
|
Look at the posts about the wizard.
It is honestly the 'worst thing' about the compiler. Anyone using it should
be taken and publicly flogged (not that I'm a violent person you understand).
It really offers little that is worth using. Encourages wrong configurations
and generates far more problems than it solves.
Have you tried shutting down the existing SPI before re-configuring?.
The SPI_INIT, adjusts what it sends based upon what it 'thinks' the
configuration currently is. |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 17, 2021 10:41 am |
|
|
Ttelmah wrote: | Look at the posts about the wizard.
It is honestly the 'worst thing' about the compiler. Anyone using it should
be taken and publicly flogged (not that I'm a violent person you understand).
It really offers little that is worth using. Encourages wrong configurations
and generates far more problems than it solves.
|
And here I was thinking that would give me the code least likely to get pushback from CCS when I report bugs!
Ttelmah wrote: |
Have you tried shutting down the existing SPI before re-configuring?.
The SPI_INIT, adjusts what it sends based upon what it 'thinks' the
configuration currently is. |
Would that actually alter the assembly code the compiler generates?
I did test with a 5.096 version and got the same results.
I'm actually down a bit of a rabbit hole at the moment. I made a short sample that can conditionally compile to use just SPI MODE 0, or just SPI 2 MODE 1, or any combination of the four I am using. I am testing to see if I can make it produce different code based on how many streams are in use.
What's interesting is that the code that generated SPI signals I could capture in the Saleae analyzer was the one that did:
Code: |
MOV #20,W4 : W4 = 20
MOV W4,262 : SPI2CON1 = W4
|
Values of 0x20 and 0x120 produce working Mode 0 and Mode 1 code that the analyzer likes and the chip I am talking to responds to.
But the compiler sometimes generates 0x3f and 0x13f, that the Saleae doesn't see. (You have to alter the Saleae Logic software setting to parse Mode 0 or Mode 1).
But these are very different settings for the SPI registers:
Code: |
111111
54321098 76543210
-------- --------
0x03f 00000000 00111111 // CLK Low to High,
0x13f 00000001 00111111 // CLK High to Low,
0x020 00000000 00100000 // CLK Low to High,
0x120 00000001 00100000 // CLK Low to High,
9 SMP: SPIx Data Input Sample Phase bit
Master mode:
1 = Input data sampled at end of data output time
0 = Input data sampled at middle of data output time
8 CKE: SPIx Clock Edge Select bit(3)
1 = Serial output data change on transition from active clock state to
Idle clock state (see bit 6)
0 = Serial output data change on transition from Idle clock state to
active clock state (see bit 6)
6 CKP: Clock Polarity Select bit
1 = Idle state for clock is a high level; active state is a low level
0 = Idle state for clock is a low level; active state is a high level
5 MSTEN: Master Mode Enable bit
1 = Master mode
0 = Slave mode
4-2 SPRE[2:0]: Secondary Prescale bits (Master mode)
1-0 PPRE[1:0]: Primary Prescale bits (Master Mode)
|
Yesterday, I was just using the variant the compiler created that worked for me. Today I am looking at the two variants and trying to figure out which one is actually correct. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Last edited by allenhuffman on Wed Feb 17, 2021 11:13 am; edited 2 times in total |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 17, 2021 10:43 am |
|
|
Just for fun, here is a sample program that can be compiled to write four 8-bit values to SPI1 or SPI2 in Mode 0 or Mode 1, depending on the defines you set.
Code: |
#include <24FJ256GA106.h>
#device ICSP=1
#use delay(clock=32MHz,crystal=8MHz)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
// Comment/uncomment the one(s) you wish to build support for.
#define USE_SPI1_MODE0
//#define USE_SPI1_MODE1
//#define USE_SPI2_MODE0
//#define USE_SPI2_MODE1
#if defined(USE_SPI1_MODE0) || defined(USE_SPI1_MODE1)
#pin_select SCK1OUT=PIN_D4
#pin_select SDI1=PIN_D5
#pin_select SDO1=PIN_D3
#endif
#if defined(USE_SPI1_MODE0)
#use spi(MASTER, SPI1, MODE=0, BITS=8, stream=SPI_MODE0)
#endif
#if defined(USE_SPI1_MODE1)
#use spi(MASTER, SPI1, MODE=1, BITS=8, stream=SPI_MODE1)
#endif
#if defined(USE_SPI2_MODE0) || defined(USE_SPI2_MODE1)
#pin_select SCK2OUT=PIN_B1
#pin_select SDI2=PIN_B2
#pin_select SDO2=PIN_B0
#endif
#if defined(USE_SPI2_MODE0)
#use spi(MASTER, SPI2, MODE=0, BITS=8, stream=SPI2_MODE0)
#endif
#if defined(USE_SPI2_MODE1)
#use spi(MASTER, SPI2, MODE=1, BITS=8, stream=SPI2_MODE1)
#endif
#pin_select U1TX=PIN_G8
#pin_select U1RX=PIN_G7
#use rs232(UART1, baud=115200, stream=TP) // Test Points
#if defined(USE_SPI1_MODE0)
void Spi1Mode0 (void)
{
spi_init (SPI_MODE0, TRUE);
spi_xfer (SPI_MODE0, 1, 8);
spi_xfer (SPI_MODE0, 2, 8);
spi_xfer (SPI_MODE0, 3, 8);
spi_xfer (SPI_MODE0, 4, 8);
}
#endif
#if defined(USE_SPI1_MODE1)
void Spi1Mode1 (void)
{
spi_init (SPI_MODE1, TRUE);
spi_xfer (SPI_MODE1, 1, 8);
spi_xfer (SPI_MODE1, 2, 8);
spi_xfer (SPI_MODE1, 3, 8);
spi_xfer (SPI_MODE1, 4, 8);
}
#endif
#if defined(USE_SPI2_MODE0)
void Spi2Mode0 (void)
{
spi_init (SPI2_MODE0, TRUE);
spi_xfer (SPI2_MODE0, 1, 8);
spi_xfer (SPI2_MODE0, 2, 8);
spi_xfer (SPI2_MODE0, 3, 8);
spi_xfer (SPI2_MODE0, 4, 8);
}
#endif
#if defined(USE_SPI2_MODE1)
void Spi2Mode1 (void)
{
spi_init (SPI2_MODE1, TRUE);
spi_xfer (SPI2_MODE1, 1, 8);
spi_xfer (SPI2_MODE1, 2, 8);
spi_xfer (SPI2_MODE1, 3, 8);
spi_xfer (SPI2_MODE1, 4, 8);
}
#endif
void main()
{
char ChoiceChar;
puts ("SPITest "__DATE__" "__TIME__);
while(TRUE)
{
puts ("");
#if defined(USE_SPI1_MODE0)
puts ("1 - SPI 1, Mode 0");
#endif
#if defined(USE_SPI1_MODE1)
puts ("2 - SPI 1, Mode 1");
#endif
#if defined(USE_SPI2_MODE0)
puts ("3 - SPI 2, Mode 0");
#endif
#if defined(USE_SPI2_MODE1)
puts ("4 - SPI 2, Mode 1");
#endif
puts ("Choose wisely: ");
ChoiceChar = getch ();
switch (ChoiceChar)
{
#if defined(USE_SPI1_MODE0)
case '1':
Spi1Mode0 ();
break;
#endif
#if defined(USE_SPI1_MODE1)
case '2':
Spi1Mode1 ();
break;
#endif
#if defined(USE_SPI2_MODE0)
case '3':
Spi2Mode0 ();
break;
#endif
#if defined(USE_SPI2_MODE1)
case '4':
Spi2Mode1 ();
break;
#endif
default:
puts ("\r\n"
"A wise choice would have beem 1-4.");
break;
}
}
}
// End of main.c
|
_________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
allenhuffman
Joined: 17 Jun 2019 Posts: 552 Location: Des Moines, Iowa, USA
|
|
Posted: Wed Feb 17, 2021 12:14 pm |
|
|
The response from CCS points to a "spi_init ()" elsewhere in my code that was changing the speed. This is troublesome because it was in a function I was not calling, so I'm baffled at why that should cause other calls to generate different code.
Still investigating. _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Feb 18, 2021 12:46 am |
|
|
It makes sense.
Remember you can prevent that from changing the code by specifying
a speed in your init.
So if you setup the MODE0 speed as a #define, using
spi_init (SPI_MODE0, MODE0SPEED);
should always give the same code generated.
Using 'true' makes it set the speed to the last one selected. Now you will
find threads here where the algorithm for deciding what the 'last' value
was can become confused, in most of this type of operation. Remember
the compiler is making this decision at compile time, not run time, so it
tends to look through the files sequentially in the order they compile, not
in the order the code flow would follow. This is why the unused init is having
the effect you see. |
|
|
|
|
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
|