Author Topic: SPI2 woes with DSPIC33E and MCC  (Read 9237 times)

0 Members and 2 Guests are viewing this topic.

Offline PrimeTopic starter

  • Regular Contributor
  • *
  • Posts: 67
  • Country: au
SPI2 woes with DSPIC33E and MCC
« on: January 02, 2017, 07:19:05 pm »
Hi,

I hope someone can help me. I'm having hassles using the SPI2 setup that comes from MCC on the DSPIC33EP256MC502.

The basic setup appears to be correct as when I independently call


 
Code: [Select]
readData = SPI2_Exchange16bit(writeData);
I can see the data out, clk and data in signals on a scope and they correspond with the readings that the MCP3002 is supposed to be making.  |O

 
This is how I currently have it setup:
 
Code: [Select]
void SPI2_Initialize (void)
{
    // MSTEN Master; DISSDO disabled; PPRE 4:1; SPRE 5:1; MODE16 enabled; SMP End; DISSCK disabled; CKP Idle:Low, Active:High; CKE Idle to Active; SSEN disabled;
    SPI2CON1 = 0x62E;
    // SPIFSD disabled; SPIBEN enabled; FRMPOL disabled; FRMDLY disabled; FRMEN disabled;
    SPI2CON2 = 0x1;
    // SISEL SPI_INT_SPIRBF; SPIROV disabled; SPIEN enabled; SPISIDL disabled;
    SPI2STAT = 0x800C;
}

with the following in code parameters:
 
Code: [Select]
    int MY_BUFER_SIZE = 2;
    uint16_t myWriteBuffer[MY_BUFER_SIZE];
    uint16_t myReadBuffer[MY_BUFER_SIZE];
    uint16_t writeData = 0b0110100000000000;
    uint16_t readData;
    SPI2_STATUS status;
    unsigned int total;
    total = 0;

 

However it is not reading in the ADC values.
 
When the code reaches

Code: [Select]
            CS0_SetLow();
            do {
                total = SPI2_Exchange16bitBuffer(&myWriteBuffer[total], MY_BUFER_SIZE - total, &myReadBuffer[total]);
                Fault_SetLow();
                // Do something else...
                //total = 16;

            } while (total < MY_BUFER_SIZE);
            Fault_SetHigh();
            readData = SPI2_Exchange16bit(writeData);

            status = SPI2_StatusGet();
            CS0_SetHigh();


it doesn't work. I've tried different values for MY_BUFER_SIZE including 0,1,2,8,16 and it never leaves the do while... loop.  :(

This comes from the SPI2.h file as an example of how to access the SPI port.

Can someone advise what might be wrong with it?

Could I have the wrong interrupt set?




I've spent 3 days at this and I'm ready to tear my hair out :(

If someone wants the complete code, I'll package and upload it.
 
 
(I've posted this on the Microchip forums as well although I think I'll have more luck here)


Thanks.
 

Offline RogerRowland

  • Regular Contributor
  • *
  • Posts: 193
  • Country: gb
    • Personal web site
Re: SPI2 woes with DSPIC33E and MCC
« Reply #1 on: January 03, 2017, 04:45:48 am »
I haven't checked what that function returns, but maybe you need to accumulate that total to get you out of the loop. So change the = to a +=, like so

Code: [Select]
            CS0_SetLow();
            do {
                total += SPI2_Exchange16bitBuffer(&myWriteBuffer[total], MY_BUFER_SIZE - total, &myReadBuffer[total]);
                Fault_SetLow();
                // Do something else...
                //total = 16;

            } while (total < MY_BUFER_SIZE);
            Fault_SetHigh();
            readData = SPI2_Exchange16bit(writeData);

            status = SPI2_StatusGet();
            CS0_SetHigh();
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5417
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #2 on: January 03, 2017, 06:58:47 am »
While I realise this doesn't directly help you, MCC is the lazy way to program, and I really cannot recommend it in any circumstances. It's buggy and in the end you have to understand the peripherals at a register level anyway. The slightly more complex peripherals like SPI and I2C shackle you to a semi-machine generated state machine which is way over complicated for 99% of use cases, and may not even be fit for your purpose anyway. It's also rarely particularly efficient.

The worst aspect is that the code is very difficult to maintain. When your requirements chnage or a new version of MCC is released, you cannot trust MCC not to overwrite your code. As it is, you risk it overwriting your code every time you run it.

So in short MCC is a crutch, and while it may seem like a great idea, frankly it ain't! I highly recommend that you get used to writing your own peripheral libraries that you can re-use and tailor as required.
 

Online JPortici

  • Super Contributor
  • ***
  • Posts: 3534
  • Country: it
Re: SPI2 woes with DSPIC33E and MCC
« Reply #3 on: January 03, 2017, 07:23:31 am »
+1
i have no idea of what happens inside those functions, i can't help with that.
anyway, you say the mcu generates and sends the correct data (you see activity on the MOSI/SCK lines) but the input buffer always returns zero. i would suspect a misconfiguration of the IOs. Ah, it once happened to me: using the two spi with adjacent ports, i swapped MOSI1 with MOSI2

try connecting out with input and send some data. you should see it return the same data you sent
 

Offline PrimeTopic starter

  • Regular Contributor
  • *
  • Posts: 67
  • Country: au
Re: SPI2 woes with DSPIC33E and MCC
« Reply #4 on: January 03, 2017, 08:34:10 am »
I haven't checked what that function returns, but maybe you need to accumulate that total to get you out of the loop. So change the = to a +=, like so

Code: [Select]
            CS0_SetLow();
            do {
                total += SPI2_Exchange16bitBuffer(&myWriteBuffer[total], MY_BUFER_SIZE - total, &myReadBuffer[total]);
                Fault_SetLow();
                // Do something else...
                //total = 16;

            } while (total < MY_BUFER_SIZE);
            Fault_SetHigh();
            readData = SPI2_Exchange16bit(writeData);

            status = SPI2_StatusGet();
            CS0_SetHigh();


Thanks. I'm going to give that a shot tonight.

If I am reading the right description, it should return 2.
 

Offline PrimeTopic starter

  • Regular Contributor
  • *
  • Posts: 67
  • Country: au
Re: SPI2 woes with DSPIC33E and MCC
« Reply #5 on: January 03, 2017, 08:49:07 am »
While I realise this doesn't directly help you, MCC is the lazy way to program, and I really cannot recommend it in any circumstances. It's buggy and in the end you have to understand the peripherals at a register level anyway. The slightly more complex peripherals like SPI and I2C shackle you to a semi-machine generated state machine which is way over complicated for 99% of use cases, and may not even be fit for your purpose anyway. It's also rarely particularly efficient.

The worst aspect is that the code is very difficult to maintain. When your requirements chnage or a new version of MCC is released, you cannot trust MCC not to overwrite your code. As it is, you risk it overwriting your code every time you run it.

So in short MCC is a crutch, and while it may seem like a great idea, frankly it ain't! I highly recommend that you get used to writing your own peripheral libraries that you can re-use and tailor as required.

Yes, that's what I try to do. But some of the documentation for the peripheral libraries is rather vague to start with and you end up scratching around in the dark anyway. I spent 3 weeks battling to get CAN working because Microchip's example programs didn't clear the receive buffer correctly. Sometimes you need "working" code to start with so that you can refine it.

+1
i have no idea of what happens inside those functions, i can't help with that.
anyway, you say the mcu generates and sends the correct data (you see activity on the MOSI/SCK lines) but the input buffer always returns zero. i would suspect a misconfiguration of the IOs. Ah, it once happened to me: using the two spi with adjacent ports, i swapped MOSI1 with MOSI2

try connecting out with input and send some data. you should see it return the same data you sent

The SPI2 port is on the peripheral pin select pins and I checked the registers. They look like they have been set correctly, but thanks  :) I also disabled the other functions on those pins in the PMD registers in case they were interfering with the pins like I had previously experienced with the PWM2 and PWM3 channels.

Here is the code for those functions

Code: [Select]
/**
  SPI2 Generated Driver API Source File

  Company:
    Microchip Technology Inc.

  File Name:
    spi2.c

  @Summary
    This is the generated source file for the SPI2 driver using MPLAB(c) Code Configurator

  @Description
    This source file provides APIs for driver for SPI2.
    Generation Information :
        Product Revision  :  MPLAB(c) Code Configurator - pic24-dspic-pic32mm : v1.25
        Device            :  dsPIC33EP256MC502
        Driver Version    :  0.5
    The generated drivers are tested against the following:
        Compiler          :  XC16 1.26
        MPLAB           :  MPLAB X 3.45
*/

/*
    (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this
    software and any derivatives exclusively with Microchip products.

    THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
    EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
    PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
    WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.

    IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
    INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
    WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
    BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
    FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
    ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
    THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

    MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
    TERMS.
*/

/**
  Section: Included Files
*/

#include <xc.h>
#include "spi2.h"


/**
 Section: File specific functions
*/

inline __attribute__((__always_inline__)) SPI2_TRANSFER_MODE SPI2_TransferModeGet(void);
void SPI2_Exchange( uint8_t *pTransmitData, uint8_t *pReceiveData );
uint16_t SPI2_ExchangeBuffer(uint8_t *pTransmitData, uint16_t byteCount, uint8_t *pReceiveData);

/**
 Section: Driver Interface Function Definitions
*/


void SPI2_Initialize (void)
{
    // MSTEN Master; DISSDO disabled; PPRE 4:1; SPRE 5:1; MODE16 enabled; SMP End; DISSCK disabled; CKP Idle:Low, Active:High; CKE Idle to Active; SSEN disabled;
    SPI2CON1 = 0x62E;
    // SPIFSD disabled; SPIBEN enabled; FRMPOL disabled; FRMDLY disabled; FRMEN disabled;
    SPI2CON2 = 0x1;
    // SISEL SPI_INT_SPIRBF; SPIROV disabled; SPIEN enabled; SPISIDL disabled;
    SPI2STAT = 0x800C;
}

void SPI2_Exchange( uint8_t *pTransmitData, uint8_t *pReceiveData )
{

    while( SPI2STATbits.SPITBF == true )
    {

    }

    if (SPI2_TransferModeGet() == SPI2_DRIVER_TRANSFER_MODE_16BIT)
        SPI2BUF = *((uint16_t*)pTransmitData);
    else
        SPI2BUF = *((uint8_t*)pTransmitData);

    while ( SPI2STATbits.SRXMPT == true);

    if (SPI2_TransferModeGet() == SPI2_DRIVER_TRANSFER_MODE_16BIT)
        *((uint16_t*)pReceiveData) = SPI2BUF;
    else
        *((uint8_t*)pReceiveData) = SPI2BUF;

}

uint16_t SPI2_ExchangeBuffer(uint8_t *pTransmitData, uint16_t byteCount, uint8_t *pReceiveData)
{

    uint16_t dataSentCount = 0;
    uint16_t count = 0;
    uint16_t dummyDataReceived = 0;
    uint16_t dummyDataTransmit = SPI2_DUMMY_DATA;

    uint8_t  *pSend, *pReceived;
    uint16_t addressIncrement;
    uint16_t receiveAddressIncrement, sendAddressIncrement;

    SPI2_TRANSFER_MODE spiModeStatus;

    spiModeStatus = SPI2_TransferModeGet();
    // set up the address increment variable
    if (spiModeStatus == SPI2_DRIVER_TRANSFER_MODE_16BIT)
    {
        addressIncrement = 2;
        byteCount >>= 1;
    }       
    else
    {
        addressIncrement = 1;
    }

    // set the pointers and increment delta
    // for transmit and receive operations
    if (pTransmitData == NULL)
    {
        sendAddressIncrement = 0;
        pSend = (uint8_t*)&dummyDataTransmit;
    }
    else
    {
        sendAddressIncrement = addressIncrement;
        pSend = (uint8_t*)pTransmitData;
    }
       
    if (pReceiveData == NULL)
    {
       receiveAddressIncrement = 0;
       pReceived = (uint8_t*)&dummyDataReceived;
    }
    else
    {
       receiveAddressIncrement = addressIncrement;       
       pReceived = (uint8_t*)pReceiveData;
    }


    while( SPI2STATbits.SPITBF == true )
    {

    }

    while (dataSentCount < byteCount)
    {
        if ((count < SPI2_FIFO_FILL_LIMIT))
        {
            if (spiModeStatus == SPI2_DRIVER_TRANSFER_MODE_16BIT)
                SPI2BUF = *((uint16_t*)pSend);
            else
                SPI2BUF = *pSend;
            pSend += sendAddressIncrement;
            dataSentCount++;
            count++;
        }

        if (SPI2STATbits.SRXMPT == false)
        {
            if (spiModeStatus == SPI2_DRIVER_TRANSFER_MODE_16BIT)
                *((uint16_t*)pReceived) = SPI2BUF;
            else
                *pReceived = SPI2BUF;
            pReceived += receiveAddressIncrement;
            count--;
        }

    }
    while (count)
    {
        if (SPI2STATbits.SRXMPT == false)
        {
            if (spiModeStatus == SPI2_DRIVER_TRANSFER_MODE_16BIT)
                *((uint16_t*)pReceived) = SPI2BUF;
            else
                *pReceived = SPI2BUF;
            pReceived += receiveAddressIncrement;
            count--;
        }
    }

    return dataSentCount;
}


uint16_t SPI2_Exchange16bit( uint16_t data )
{
    uint16_t receiveData;

    SPI2_Exchange((uint8_t*)&data, (uint8_t*)&receiveData);

    return (receiveData);
}

uint16_t SPI2_Exchange16bitBuffer(uint16_t *dataTransmitted, uint16_t byteCount, uint16_t *dataReceived)
{
    return (SPI2_ExchangeBuffer((uint8_t*)dataTransmitted, byteCount, (uint8_t*)dataReceived));
}


/**

    The module's transfer mode affects the operation
    of the exchange functions. The table below shows
    the effect on data sent or received:
    |=======================================================================|
    | Transfer Mode  |     Exchange Function      |        Comments         |
    |=======================================================================|
    |                | SPIx_Exchange8bitBuffer()  |                         |
    |                |----------------------------|  OK                     |
    |                | SPIx_Exchange8bit()        |                         |
    |     8 bits     |----------------------------|-------------------------|
    |                | SPIx_Exchange16bitBuffer() | Do not use. Only the    |
    |                |----------------------------| lower byte of the 16-bit|
    |                | SPIx_Exchange16bit()       | data will be sent or    |
    |                |                            | received.               |
    |----------------|----------------------------|-------------------------|
    |                | SPIx_Exchange8bitBuffer()  | Do not use. Additional  |
    |                |----------------------------| data byte will be       |
    |                | SPIx_Exchange8bit()        | inserted for each       |
    |                |                            | 8-bit data.             |
    |     16 bits    |----------------------------|-------------------------|
    |                | SPIx_Exchange16bitBuffer() |                         |
    |                |----------------------------|  OK                     |
    |                | SPIx_Exchange16bit()       |                         |
    |----------------|----------------------------|-------------------------|
*/
inline __attribute__((__always_inline__)) SPI2_TRANSFER_MODE SPI2_TransferModeGet(void)
{
if (SPI2CON1bits.MODE16 == 0)
        return SPI2_DRIVER_TRANSFER_MODE_8BIT;
    else
        return SPI2_DRIVER_TRANSFER_MODE_16BIT;
}


SPI2_STATUS SPI2_StatusGet()
{
    return(SPI2STAT);
}
/**
 End of File
*/


 

Online JPortici

  • Super Contributor
  • ***
  • Posts: 3534
  • Country: it
Re: SPI2 woes with DSPIC33E and MCC
« Reply #6 on: January 03, 2017, 11:27:45 am »
and the input pin is set to digital, right?
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5417
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #7 on: January 03, 2017, 12:04:37 pm »
While I realise this doesn't directly help you, MCC is the lazy way to program, and I really cannot recommend it in any circumstances. It's buggy and in the end you have to understand the peripherals at a register level anyway. The slightly more complex peripherals like SPI and I2C shackle you to a semi-machine generated state machine which is way over complicated for 99% of use cases, and may not even be fit for your purpose anyway. It's also rarely particularly efficient.

The worst aspect is that the code is very difficult to maintain. When your requirements chnage or a new version of MCC is released, you cannot trust MCC not to overwrite your code. As it is, you risk it overwriting your code every time you run it.

So in short MCC is a crutch, and while it may seem like a great idea, frankly it ain't! I highly recommend that you get used to writing your own peripheral libraries that you can re-use and tailor as required.

Yes, that's what I try to do. But some of the documentation for the peripheral libraries is rather vague to start with and you end up scratching around in the dark anyway. I spent 3 weeks battling to get CAN working because Microchip's example programs didn't clear the receive buffer correctly. Sometimes you need "working" code to start with so that you can refine it.

For SPI and I2C, you're better off talking to the bare metal from your own libraries, and avoid using vendor or 3rd party peripheral libraries. I've lost count of the number of iterations of incompatible peripheral libraries Microchip have come out with over the years, completely deprecating older incarnations. MCC takes this built in obsolescence to a whole new level though!

This is not to be confused with taking existing, working code and manipulating it for your own means, I am sure we all do that to some degree. Particularly regarding CAN, it's a more complex peripheral and typically it's implemented with a software stack built on top of it. In general I'd absolutely take some working code and build on that.

I2C and particularly SPI are not that hard, and are certainly less hard than trying to debug and reverse engineer some machine generated code!
« Last Edit: January 03, 2017, 12:39:54 pm by Howardlong »
 

Offline void_error

  • Frequent Contributor
  • **
  • Posts: 673
  • Country: ro
  • I can transistor...
Re: SPI2 woes with DSPIC33E and MCC
« Reply #8 on: January 03, 2017, 12:31:57 pm »
While I realise this doesn't directly help you, MCC is the lazy way to program, and I really cannot recommend it in any circumstances. It's buggy and in the end you have to understand the peripherals at a register level anyway. The slightly more complex peripherals like SPI and I2C shackle you to a semi-machine generated state machine which is way over complicated for 99% of use cases, and may not even be fit for your purpose anyway. It's also rarely particularly efficient.

The worst aspect is that the code is very difficult to maintain. When your requirements chnage or a new version of MCC is released, you cannot trust MCC not to overwrite your code. As it is, you risk it overwriting your code every time you run it.

So in short MCC is a crutch, and while it may seem like a great idea, frankly it ain't! I highly recommend that you get used to writing your own peripheral libraries that you can re-use and tailor as required.
I totally agree. MCC is useful though if you're too lazy write most of the code - not to be confused with use MCC so you don't write any code. I mostly use it to get something working really fast - generate the code using MCC then take the parts I need and adapt them to my application or just use (look at) it for a few ideas for peripherals I haven't used before. So far I've never used MCC generated code anywhere. Over the years I've built up my own libraries and use those with some application specific variations from time to time.
Trust me, I'm NOT an engineer.
 

Offline Buriedcode

  • Super Contributor
  • ***
  • Posts: 1694
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #9 on: January 03, 2017, 06:00:05 pm »
I totally agree. MCC is useful though if you're too lazy write most of the code - not to be confused with use MCC so you don't write any code. I mostly use it to get something working really fast - generate the code using MCC then take the parts I need and adapt them to my application or just use (look at) it for a few ideas for peripherals I haven't used before. So far I've never used MCC generated code anywhere. Over the years I've built up my own libraries and use those with some application specific variations from time to time.

This.  I was skeptical, but ended up using it anyway for the convenience of setting up IO ports and timers.  But ultimately it pays to take 15 minutes to take the bits you need and remove the dependency.  I did knock up my own little app many moons ago to set up peripherals, but as the number of devices I used went up, it became a sod to keep track of all the device differences.  I wonder if there's any call for an open source alternative?  Same sort of thing, without the bloat.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5417
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #10 on: January 03, 2017, 10:05:46 pm »
So I did actually spend quite some time using MCC some months ago, in an effort to see if it really was worth it. I was open minded, in fact I was more than that, it seemed such an obvious solution on the surface. But after some time I changed my mind.

As well as the points I already mentioned, I totally dislike being pushed into arranging my code the way the machine or framework sees fit.

Say you want to share and demonstrate example code to show the problem, typically you have to distribute a dozen files to make it buildable. Almost always a single file with the bare minimum to reproduce a problem is more productive. You can't do,that with MCC.

I don't like the way it sets up the peripheral registers without separating out the fields. MCC is so bug ridden, it frequently gets the individual field assignments wrong. It's a PITA to identify and fix!

In the end it's untrustworthy, and I was spending more time debugging the generated code than I was being productive. The lack of backward compatibilty every time they release a new build, regression of bugs, and general lack of maintainability means your code is going to need to be regression tested and reworked each time they release a new version to fix the bugs of previous versions.

Fundamentally, code generators that force you to structure your code in an excessively dictatorial way is the wrong direction to go, buggy or not. The same applies to an even greater extent to Harmony. You end up wasting too much time trying to understand very proprietary tools, and second guessing those tools when you could've written it yourself and had a much greater understanding of what you're doing. Unfortunately for very complex peripherals like USB and Ethernet, you are almost always dependent on vendor supplied libraries.

While I understand the sentiment, I am reluctant to recommend coming up with an open source solution to peripheral libraries. Microchip discovered that they are rarely fit for purpose after a couple of chip iterations, so have to try again. Coming up with your own implementations may seem like reinventing the wheel, but you have little choice but to understand the non-complex peripherals at the hardware and register level anyway for anything but the most trivial examples. For the more complex peripherals, yes, a standard, well designed and characterised API would be welcome, but the push towards a dictatorial and unmaintainable framework mentality can be left at the door thanks!
 

Offline Buriedcode

  • Super Contributor
  • ***
  • Posts: 1694
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #11 on: January 03, 2017, 11:09:56 pm »
I didn't mean to derail the thread bashing the MCC.  My (shitty) 2007ish version was a generic windows GUI that just spat out a C file template leaving the 'main' blank - defines weren't in a header. Also didn't' have anything like interrupt handling or ring buffers for the USART but did have timer0/1/2 calculators built in.  Come to think of it, it was quite handy!  It was really because I was tired of setting the TRIS register, read-write-modify for IO's (which were all macros), oscillator, timer setup, SPI etc...  I can easily see why many vendors have used such a thing, a point and click GUI for basic projects where all IO's are fixed, but I didn't extend it to complicated peripherals because any 'config' GUI would belie the peripherals' versatility (the exception here is the CLC module, where I really can't do without the tool).

For 16F/18F projects, I used MPLABX a few times, but switched back to MikroC - where the libraries are closed (really not a good thing, but you can always just write you're own as I was doing).  Taking a while to find how to see the generated assembly and seeing some of the tripe XC8 kicks out sealed the deal.  Still installed though, MCC has the ability to create a very *simple* project quickly (think Arduino style stuff, sniffing SPI and sending it to terminal, or displaying on an LCD).  As soon as you want to do anything more and it ends up becoming a burden.

So yes, I didn't think there was much interest in an alternative, didn't hurt to put it out there though!  Cheers
« Last Edit: January 03, 2017, 11:12:17 pm by Buriedcode »
 

Offline PrimeTopic starter

  • Regular Contributor
  • *
  • Posts: 67
  • Country: au
Re: SPI2 woes with DSPIC33E and MCC
« Reply #12 on: January 05, 2017, 12:29:43 pm »
And the answer is... "MCC does not support SPI in interrupt mode. "

This came through in the new MCC configurator update  :--


I didn't mean to derail the thread bashing the MCC.  My (shitty) 2007ish version was a generic windows GUI that just spat out a C file template leaving the 'main' blank - defines weren't in a header. Also didn't' have anything like interrupt handling or ring buffers for the USART but did have timer0/1/2 calculators built in.  Come to think of it, it was quite handy!  It was really because I was tired of setting the TRIS register, read-write-modify for IO's (which were all macros), oscillator, timer setup, SPI etc...  I can easily see why many vendors have used such a thing, a point and click GUI for basic projects where all IO's are fixed, but I didn't extend it to complicated peripherals because any 'config' GUI would belie the peripherals' versatility (the exception here is the CLC module, where I really can't do without the tool).

For 16F/18F projects, I used MPLABX a few times, but switched back to MikroC - where the libraries are closed (really not a good thing, but you can always just write you're own as I was doing).  Taking a while to find how to see the generated assembly and seeing some of the tripe XC8 kicks out sealed the deal.  Still installed though, MCC has the ability to create a very *simple* project quickly (think Arduino style stuff, sniffing SPI and sending it to terminal, or displaying on an LCD).  As soon as you want to do anything more and it ends up becoming a burden.

So yes, I didn't think there was much interest in an alternative, didn't hurt to put it out there though!  Cheers

Setting up the macros and direction registers and peripheral pins is where I find it most useful.

Mikro-Electronica have really nice development kits. They are along the same veins as the STK500 and STK600 rather than the explorer 16 which I find a bit useless.

So I did actually spend quite some time using MCC some months ago, in an effort to see if it really was worth it. I was open minded, in fact I was more than that, it seemed such an obvious solution on the surface. But after some time I changed my mind.

As well as the points I already mentioned, I totally dislike being pushed into arranging my code the way the machine or framework sees fit.

Say you want to share and demonstrate example code to show the problem, typically you have to distribute a dozen files to make it buildable. Almost always a single file with the bare minimum to reproduce a problem is more productive. You can't do,that with MCC.

I don't like the way it sets up the peripheral registers without separating out the fields. MCC is so bug ridden, it frequently gets the individual field assignments wrong. It's a PITA to identify and fix!

In the end it's untrustworthy, and I was spending more time debugging the generated code than I was being productive. The lack of backward compatibilty every time they release a new build, regression of bugs, and general lack of maintainability means your code is going to need to be regression tested and reworked each time they release a new version to fix the bugs of previous versions.

Fundamentally, code generators that force you to structure your code in an excessively dictatorial way is the wrong direction to go, buggy or not. The same applies to an even greater extent to Harmony. You end up wasting too much time trying to understand very proprietary tools, and second guessing those tools when you could've written it yourself and had a much greater understanding of what you're doing. Unfortunately for very complex peripherals like USB and Ethernet, you are almost always dependent on vendor supplied libraries.

While I understand the sentiment, I am reluctant to recommend coming up with an open source solution to peripheral libraries. Microchip discovered that they are rarely fit for purpose after a couple of chip iterations, so have to try again. Coming up with your own implementations may seem like reinventing the wheel, but you have little choice but to understand the non-complex peripherals at the hardware and register level anyway for anything but the most trivial examples. For the more complex peripherals, yes, a standard, well designed and characterised API would be welcome, but the push towards a dictatorial and unmaintainable framework mentality can be left at the door thanks!

I happen to like the code structure although I really wish they'd put proper commentary in all their code (and that goes for data sheets too). I'm happy splitting code into header files and keeping the bare minimum in the main file. But I would prefer if they used binary to set up registers as it would be a lot clearer to read than hex.


 

Online JPortici

  • Super Contributor
  • ***
  • Posts: 3534
  • Country: it
Re: SPI2 woes with DSPIC33E and MCC
« Reply #13 on: January 05, 2017, 12:49:19 pm »
For 16F/18F projects, I used MPLABX a few times, but switched back to MikroC

just curious: have you ever compared (recent versions of) mikro C and XC8? i haven't used mikroc in ages so i don't remember, but i'd be curious to see how better or worse is mikroc output assembly. i suppose better as XC8 free is atrocious and adds pointless instruction at almost every occasion.
 

Offline Buriedcode

  • Super Contributor
  • ***
  • Posts: 1694
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #14 on: January 05, 2017, 07:05:06 pm »
For 16F/18F projects, I used MPLABX a few times, but switched back to MikroC

just curious: have you ever compared (recent versions of) mikro C and XC8? i haven't used mikroc in ages so i don't remember, but i'd be curious to see how better or worse is mikroc output assembly. i suppose better as XC8 free is atrocious and adds pointless instruction at almost every occasion.

I don't have the latest mikroC, just an old PRO version, and the assembly is very neat - I could not find any convoluted loops or unnecessary code, every version was surprisingly optimized.  Loops, switch-case were all pretty much as I would have written them back when I did assembly. With that said I found a bug (mikroC PRO 6.4 I think..) that was pretty critical - an IF statement generated assembly that checked for a value of 0 and continued on regardless of the result. I'll send a screenshot i you're curious, but it seems incredibly rare.

I will have to do a comparison using a project that doesn't use any built-in libraries but the last mikroC project I did that was also attempted in XC8 was an 8 channel 433MHz remote system, using the sort of PWM channel coding found in the PT2262 (to allow for cheap chinese remotes to be used).  IIRC, XC8's code was significantly larger and used up more RAM.  The mikroC version (pretty much the same code) I had bags of memory left over.

Not trying to be a fanboy but I can easily see why people love that compiler.  The closed libraries means it will never be for open source projects but for personal projects, or even commercial ones, its convenient and efficient.  I'll still use both XC8 (because its 'free' and more common) and MikroC, but I'm looking for an alternative to both.
 

Offline PrimeTopic starter

  • Regular Contributor
  • *
  • Posts: 67
  • Country: au
Re: SPI2 woes with DSPIC33E and MCC
« Reply #15 on: January 05, 2017, 11:58:05 pm »
So I rewrote the code using what I could find in the data sheet and online,  no luck.

Data goes out, data comes back. Data is not being loaded into the micro.

Jtag is disabled. SPI1 is disabled, I2C is disabled.

I'll trying SPI1 in the morning. SPI1 is hard coded to those pins. SPI2 is mapped to them.

Is it possible SPI1 could be interfering with SPI2?
 

Online JPortici

  • Super Contributor
  • ***
  • Posts: 3534
  • Country: it
Re: SPI2 woes with DSPIC33E and MCC
« Reply #16 on: January 06, 2017, 09:28:14 am »
I don't have the latest mikroC, just an old PRO version, and the assembly is very neat - I could not find any convoluted loops or unnecessary code, every version was surprisingly optimized.  Loops, switch-case were all pretty much as I would have written them back when I did assembly. With that said I found a bug (mikroC PRO 6.4 I think..) that was pretty critical - an IF statement generated assembly that checked for a value of 0 and continued on regardless of the result. I'll send a screenshot i you're curious, but it seems incredibly rare.

I will have to do a comparison using a project that doesn't use any built-in libraries but the last mikroC project I did that was also attempted in XC8 was an 8 channel 433MHz remote system, using the sort of PWM channel coding found in the PT2262 (to allow for cheap chinese remotes to be used).  IIRC, XC8's code was significantly larger and used up more RAM.  The mikroC version (pretty much the same code) I had bags of memory left over.

Not trying to be a fanboy but I can easily see why people love that compiler.  The closed libraries means it will never be for open source projects but for personal projects, or even commercial ones, its convenient and efficient.  I'll still use both XC8 (because its 'free' and more common) and MikroC, but I'm looking for an alternative to both.
well a free-free comparison would be more significant. i'm sure XC8 pro produces code as clean as mikro c.
I remember i dropped mikro c a long time ago because they couldn't keep up with new chips (new as in "came out last year or two")
but i first learned pics on mikrobasic, it helped me a lot at the beginning.
Anyway, i googled a bit for a comparison of the two.. didn't find out about difference in generated code but one crucial weakness of both is found:
- MikroC store constants in flash and loads them in ram at startup :palm: hopefully it can be disable like variable initialization, otherwise i couldn't be able to write a single program (some kb of tables)
- XC8 for pic 18 has this retarded macro way of storing constant in eeprom as there should be ways to tell the programmer to put them that... and deleted the standard libraries while keeping the macros... EMPTY. JESUS CHRIST MICROCHIP. (*yes yes it is almost common knowledge but for the new user it should be infuriating)

So I rewrote the code using what I could find in the data sheet and online,  no luck.

Data goes out, data comes back. Data is not being loaded into the micro.

Jtag is disabled. SPI1 is disabled, I2C is disabled.

I'll trying SPI1 in the morning. SPI1 is hard coded to those pins. SPI2 is mapped to them.

Is it possible SPI1 could be interfering with SPI2?
i still think there is a problem in your pin configuration.
you are sure that the PPS was set tup correctly?
is the pin set for input?
is the analog channel disabled?
 

Offline Buriedcode

  • Super Contributor
  • ***
  • Posts: 1694
  • Country: gb
Re: SPI2 woes with DSPIC33E and MCC
« Reply #17 on: January 06, 2017, 10:07:26 pm »
Although I dont' believe I have that device to hand (I have been swimming in PIC's and AVR's for a while now.. ) if you can, I woudl say post your entire code - save the parts that relate in no way to SPI.

Or have you just written a test program purely for the SPI port? That would have been my first choice.  That way I almost always find where I've gone wrong, what I've missed or.. on the really rare occasion - and actual bug in the libraries.
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 855
Re: SPI2 woes with DSPIC33E and MCC
« Reply #18 on: January 07, 2017, 12:17:34 am »
MCC sure knows how to generate unreadable code.


Quote
total += SPI2_Exchange16bitBuffer(&myWriteBuffer[total], MY_BUFFER_SIZE - total, &myReadBuffer[total]);

That second argument is not used correctly (easy mistake thanks to MCC)- it is a BYTE count, and you are using it as a WORD count. Inside that function, if in 16bit mode that byteCount gets converted to a WORD count. If you passed a BYTE count of MY_BUFFER_SIZE - total (2 - 0), that gets converted to a word count of 1, total returns 1 (WORD count), total is less than MY_BUFFER_SIZE, so do again, but now MY_BUFFER_SIZE - total (2 -1) is incorrect and will get converted to a word count of 0- which means nothing is sent and the function returns 0- total is still 1, though and will continue to be 1 (therefore stuck in loop).

do this instead (if you want to do a word at a time instead of whole buffer)-
Quote
total += SPI2_Exchange16bitBuffer(&myWriteBuffer[total], 2, &myReadBuffer[total]);
fyi- the return value will always equal the second argument if in byte mode, or the second argument>>1 if in 16bit mode, so you could simply do this also-
Quote
SPI2_Exchange16bitBuffer(&myWriteBuffer[total], 2, &myReadBuffer[total]);
total++;

I'm not sure why MCC has to always make things twice as complicated as they need to be, if they could generate simple, readable code something like this-
https://gist.github.com/anonymous/aa66874527652f67f29e07ebdca9f7a0
it would be more useful. They make one large generic overly complicated function that works for 8/16bit mode with helper functions specifically for 16bit mode in this case (I don't see the 8bit helper functions generated, so why even bother to create a generic 8/16bit function?). In most cases, it takes twice as long to figure out their code than to just create your own.

« Last Edit: January 07, 2017, 10:27:14 pm by cv007 »
 

Offline PrimeTopic starter

  • Regular Contributor
  • *
  • Posts: 67
  • Country: au
Re: SPI2 woes with DSPIC33E and MCC
« Reply #19 on: January 09, 2017, 07:32:09 pm »
I don't have the latest mikroC, just an old PRO version, and the assembly is very neat - I could not find any convoluted loops or unnecessary code, every version was surprisingly optimized.  Loops, switch-case were all pretty much as I would have written them back when I did assembly. With that said I found a bug (mikroC PRO 6.4 I think..) that was pretty critical - an IF statement generated assembly that checked for a value of 0 and continued on regardless of the result. I'll send a screenshot i you're curious, but it seems incredibly rare.

I will have to do a comparison using a project that doesn't use any built-in libraries but the last mikroC project I did that was also attempted in XC8 was an 8 channel 433MHz remote system, using the sort of PWM channel coding found in the PT2262 (to allow for cheap chinese remotes to be used).  IIRC, XC8's code was significantly larger and used up more RAM.  The mikroC version (pretty much the same code) I had bags of memory left over.

Not trying to be a fanboy but I can easily see why people love that compiler.  The closed libraries means it will never be for open source projects but for personal projects, or even commercial ones, its convenient and efficient.  I'll still use both XC8 (because its 'free' and more common) and MikroC, but I'm looking for an alternative to both.
well a free-free comparison would be more significant. i'm sure XC8 pro produces code as clean as mikro c.
I remember i dropped mikro c a long time ago because they couldn't keep up with new chips (new as in "came out last year or two")
but i first learned pics on mikrobasic, it helped me a lot at the beginning.
Anyway, i googled a bit for a comparison of the two.. didn't find out about difference in generated code but one crucial weakness of both is found:
- MikroC store constants in flash and loads them in ram at startup :palm: hopefully it can be disable like variable initialization, otherwise i couldn't be able to write a single program (some kb of tables)
- XC8 for pic 18 has this retarded macro way of storing constant in eeprom as there should be ways to tell the programmer to put them that... and deleted the standard libraries while keeping the macros... EMPTY. JESUS CHRIST MICROCHIP. (*yes yes it is almost common knowledge but for the new user it should be infuriating)

So I rewrote the code using what I could find in the data sheet and online,  no luck.

Data goes out, data comes back. Data is not being loaded into the micro.

Jtag is disabled. SPI1 is disabled, I2C is disabled.

I'll trying SPI1 in the morning. SPI1 is hard coded to those pins. SPI2 is mapped to them.

Is it possible SPI1 could be interfering with SPI2?
i still think there is a problem in your pin configuration.
you are sure that the PPS was set tup correctly?
is the pin set for input?
is the analog channel disabled?

I'm pretty certain unless I've missed something. Take a look if you can and see?

As the data comes out the micro and goes into the the ADC, and then the correct answer comes out the ADC, I'm pretty certain that everything else is right.

I also posted a picture of the microcontroller. (The descriptions refer to the connections on the ADC rather than the data directions of the microcontroller. )

I also attached the code. I've tried SPI1 and SPI2. I have had the same result with both.

I've got some other SPI versions to try from the local Microchip rep.

MCC sure knows how to generate unreadable code.


Quote
total += SPI2_Exchange16bitBuffer(&myWriteBuffer[total], MY_BUFFER_SIZE - total, &myReadBuffer[total]);

That second argument is not used correctly (easy mistake thanks to MCC)- it is a BYTE count, and you are using it as a WORD count. Inside that function, if in 16bit mode that byteCount gets converted to a WORD count. If you passed a BYTE count of MY_BUFFER_SIZE - total (2 - 0), that gets converted to a word count of 1, total returns 1 (WORD count), total is less than MY_BUFFER_SIZE, so do again, but now MY_BUFFER_SIZE - total (2 -1) is incorrect and will get converted to a word count of 0- which means nothing is sent and the function returns 0- total is still 1, though and will continue to be 1 (therefore stuck in loop).

do this instead (if you want to do a word at a time instead of whole buffer)-
Quote
total += SPI2_Exchange16bitBuffer(&myWriteBuffer[total], 2, &myReadBuffer[total]);
fyi- the return value will always equal the second argument if in byte mode, or the second argument>>1 if in 16bit mode, so you could simply do this also-
Quote
SPI2_Exchange16bitBuffer(&myWriteBuffer[total], 2, &myReadBuffer[total]);
total++;


I'm not sure why MCC has to always make things twice as complicated as they need to be, if they could generate simple, readable code something like this-
https://gist.github.com/anonymous/aa66874527652f67f29e07ebdca9f7a0
it would be more useful. They make one large generic overly complicated function that works for 8/16bit mode with helper functions specifically for 16bit mode in this case (I don't see the 8bit helper functions generated, so why even bother to create a generic 8/16bit function?). In most cases, it takes twice as long to figure out their code than to just create your own.



I'm only working with 2 bytes or 1 word? but which ever I put in, I only seem to get 1 or 0 out of.

Wow, that does look a lot clearer.


I think it just renames the code for 8bit code and drops some of the settings. I had a brief look at the 8 it setup but it wasn't illuminating.  :-//

I'll give those functions a bash. Thanks
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 855
Re: SPI2 woes with DSPIC33E and MCC
« Reply #20 on: January 10, 2017, 01:01:48 am »
Just going by what is in your zip file-
as my previous post says, you will never get out of that do loop as you are following the example code in the spi header.

The header example is bad, lets review-
    uint16_t myWriteBuffer[MY_BUFFER_SIZE];
    uint16_t myReadBuffer[MY_BUFFER_SIZE];
    uint16_t writeData;
    uint16_t readData;
    SPI1_STATUS status;
    unsigned int total;
    SPI1_Initialize;
    total = 0;
    do
    {
        total  = SPI1_Exchange16bitBuffer( &myWriteBuffer[total], MY_BUFFER_SIZE - total, &myWriteBuffer[total]);

        // Do something else...

    } while( total < MY_BUFFER_SIZE );

   
leaving aside the question of why they are not using myReadBuffer here, lets start with what SPI1_Exchange16bitBuffer is supposed to return according to the header-

  @Summary
    Returns the value of the status register of SPI instance : 1

   
but if you look at the source of SPI1_Exchange16bitBuffer, it calls SPI1_ExchangeBuffer, so if we look at that we find that it returns dataSentCount (not spi status).

if you work your way through 'SPI1_ExchangeBuffer' you will find 'while (dataSentCount < byteCount)', so effectively what returns is 'byteCount'.

what is byteCount? it is the BYTE count of what we want sent through spi, and you will see it gets converted to a WORD count (I'm calling 16bit a WORD here) IF in 16bit mode-

if (spiModeStatus == SPI1_DRIVER_TRANSFER_MODE_16BIT)
    {
        addressIncrement = 2;
        byteCount >>= 1;
    }

   
OK, back to the do loop-
total = 0
MY_BUFFER_SIZE = 2

first time through-
total = SPI1_Exchange16bitBuffer( &myWriteBuffer[0], 2 - 0, &myWriteBuffer[0]);

the byteCount was converted to 1 (2>>1 = 1)
total is now set to 1 (return value is always same as converted byteCount)

second time through-
total = SPI1_Exchange16bitBuffer( &myWriteBuffer[1], 2 - 1, &myWriteBuffer[1]);

the byteCount was converted to 0 (1>>1 = 0)
total is now set to 0 (return value is always same as converted byteCount)

as you can see, total will never increment to get out of the do loop, and in the bad example here you will actually get 1 word repeatedly sent (total keeps changing from 1 to 0)
if you 'fix' one problem they have and use 'total +=', in this case the result will be that total will get stuck at 1 so only 1 word would be sent

however, if you do as I posted previously
total += SPI1_Exchange16bitBuffer(&myWriteBuffer[total], 2, &myReadBuffer[total]);
(switching to SPI1, since you are using SPI1 now)
total will increment by 1 every time through, and you will no longer be stuck in that do loop

(I would add, the code I linked to is not tested and could be wrong, it was just to show the type of code  MCC should generate)
« Last Edit: January 10, 2017, 01:09:09 am by cv007 »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf