CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

5.102: spi_init() can generate different code

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
allenhuffman



Joined: 17 Jun 2019
Posts: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

5.102: spi_init() can generate different code
PostPosted: Tue Feb 16, 2021 1:57 pm     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
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: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Feb 16, 2021 2:21 pm     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
www.whywouldyouwanttodothat.com ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21452

View user's profile Send private message

PostPosted: Wed Feb 17, 2021 1:40 am     Reply with quote

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: 17221

View user's profile Send private message

PostPosted: Wed Feb 17, 2021 2:13 am     Reply with quote

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: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 17, 2021 7:54 am     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 17, 2021 8:44 am     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 17, 2021 8:55 am     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
www.whywouldyouwanttodothat.com ?
Ttelmah



Joined: 11 Mar 2010
Posts: 17221

View user's profile Send private message

PostPosted: Wed Feb 17, 2021 9:07 am     Reply with quote

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).
Very Happy

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: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 17, 2021 10:41 am     Reply with quote

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).
Very Happy

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
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: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 17, 2021 10:43 am     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
www.whywouldyouwanttodothat.com ?
allenhuffman



Joined: 17 Jun 2019
Posts: 481
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 17, 2021 12:14 pm     Reply with quote

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) www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC programmer.
www.whywouldyouwanttodothat.com ?
Ttelmah



Joined: 11 Mar 2010
Posts: 17221

View user's profile Send private message

PostPosted: Thu Feb 18, 2021 12:46 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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