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 CCS Technical Support

Problem using SPI communication inside of interrupt TIMER0

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



Joined: 18 Oct 2016
Posts: 9

View user's profile Send private message

Problem using SPI communication inside of interrupt TIMER0
PostPosted: Wed Feb 15, 2017 7:33 am     Reply with quote

I'm trying to use SPI communication inside of interrupt but it's not work well.

Code:
Code:


#include <18F4550.h>   // including  PIC library
#fuses XTPLL,USBDIV,CPUDIV1,VREGEN, MCLR, NODEBUG, PLL1, NOPUT
#device adc=10
#use delay(clock = 48M)
#use fast_io(B)
#include <usb_cdc.h>   // including USB library

#INT_TIMER0
void tempo(void)
{
           output_high(pin_D1); //LED high to indicate interrupt
           
            output_low(pin_A5);  // CS low
            spi_write(96);       // command write conf register
            spi_write(48);       // set up  XTALEN=1 and EN24BIT=1
            output_high(pin_A5); //CS high
           
            delay_ms(200);     //just to see the LED blink
            output_low(pin_D1); //LED high to indicate interrupt
}

 

void main(){


  set_tris_c (1); // set port C as input
/*______________________________________________________________________________
                           
                               Config SPI
______________________________________________________________________________*/
   setup_spi(spi_master|spi_h_to_l|spi_clk_div_4 );      //set up SPI library
   delay_ms(100);
   output_high(pin_A5); //CS high


  enable_interrupts(INT_TIMER0|GLOBAL);  // enable interrupt TIMER0
  setup_timer_0 (RTCC_DIV_256 | RTCC_INTERNAL);
 
  set_timer0(0);

  while (true){
   }
}


I could compile the code, when running on the PIC the interruption happens because it is possible to see with the LED, but the bytes to be sent via SPI do not send.
Has anyone ever had a similar problem?

Thank for any help in advance.
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Feb 15, 2017 8:14 am     Reply with quote

rules that MUST be obeyed when using interrupts...

1) Never EVER put ANY delays in the ISR !

this...
delay_ms(200); //just to see the LED blink
... MUSt be removed from your ISR

2) never EVER put any 'math' code in an ISR
3) never EVER put any 'print' code in an ISR
4) never EVER put any code that is 'slow' in an ISR

An ISR needs to be FAST so simply set a 'flag',maybe clear a counter or two,but get out FAST !

In main() test the 'flag' and do what's required.

something like

if 'flag' is set then
send spi data...
flash led...
clear 'flag'...



also..
this...
set_tris_c (1); // set port C as input

... does not set Port C to all inputs.

1 = 0b00000001 so only PortC.bit0 will be set as input(1=input,0=output)

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Wed Feb 15, 2017 8:35 am     Reply with quote

Though I agree wholeheartedly the reason it doesn't work is much simpler.

You are not setting up the interrupt properly. You can't 'OR' the interrupt enables.
Where things can be OR'ed together they tell you this in the include file...

There is also a problem (will depend on your chip), but you are raising CS before the second byte has transmitted. Bytes are sent to the buffer, but transmission takes time. If you want to wait for transmission to complete, you have to read the returned byte.
mquemelli



Joined: 18 Oct 2016
Posts: 9

View user's profile Send private message

PostPosted: Wed Feb 15, 2017 9:55 am     Reply with quote

I have changed as Jay said by testing with the flag:

Code:

#include <18F4550.h>   // including  PIC library
#fuses XTPLL,USBDIV,CPUDIV1,VREGEN, MCLR, NODEBUG, PLL1, NOPUT
#device adc=10
#use delay(clock = 48M)
#use fast_io(B)
#include <usb_cdc.h>   // including USB library


void main(){
/*______________________________________________________________________________
                           
                               Config SPI
______________________________________________________________________________*/
   setup_spi(spi_master|spi_h_to_l|spi_clk_div_4 );      //set up SPI library
   delay_ms(10);
   output_high(pin_A5);                                  // CS high
 
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER0);
   
   setup_timer_0 (RTCC_DIV_256|RTCC_INTERNAL);
   set_timer0(0);

 while (true){
   
           if(interrupt_active (INT_TIMER0)){

            output_low(pin_A5);  // CS low
            spi_write(96);       // command write conf register
            spi_write(48);       // set up  XTALEN=1 and EN24BIT=1
            output_high(pin_A5); //CS high

           }
           
   
     
   } // while
 
 
}//main




But still don't work.
Ttelmah, I can enable interrupt with OR logic as well as on two separate command lines. This worked, I already tested the interrupt without SPI. And the SPI communication itself also works, the problem is when I enable the interrupt. I can even use the timer0 (without the interrupt, only the counter), however when I enable interrupt the communication stop.
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Wed Feb 15, 2017 10:13 am     Reply with quote

You are now enabling interrupts without an interrupt handler. You must _never_ do this.

Interrupts do not need to be enabled to be polled. Enabling them is what allows them to call the handler routine.

You also will need to clear the interrupt each time it has been seen as going active:
Code:

   int8 dummy;
   //enable_interrupts(GLOBAL);
   //enable_interrupts(INT_TIMER0);
   //Never enable interrupts without a handler
   
   setup_timer_0 (RTCC_DIV_256|RTCC_INTERNAL);
   set_timer0(0);

   while (true)
   {
   
       if (interrupt_active (INT_TIMER0))
       {
             clear_interrupt(INT_TIMER0); //otherwise it'll never clear
             output_low(pin_A5);  // CS low
             spi_write(96);       // command write conf register
             dummy=spi_write(48);       // set up  XTALEN=1 and EN24BIT=1
             //loading the 'dummy' value here ensure the write has
             //actually completed
             output_high(pin_A5); //CS high
       }


Polling the interrupt is actually faster than using an interrupt handler, and avoids a lot of problems!...
mquemelli



Joined: 18 Oct 2016
Posts: 9

View user's profile Send private message

PostPosted: Wed Feb 15, 2017 6:27 pm     Reply with quote

I would like to thank for your help Ttelmah and Jay. I found the problem in the code, #use fast_io (B) was making communication impossible. When I removed this line, everything worked correctly.
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Feb 15, 2017 6:41 pm     Reply with quote

Using fast_io() is generally not required for 99.99% of programs posted here. Letting the CCS compiler use the default standard_io() is always the best choice unless you a) correctly configure the I/O ports AND b) you need ultra fast speed.
with a) YOU have 100% control over the I/O ports and assign their direction ( I or O) on a pin by pin level. That's great until you change the layout of the PCB, swap 2 pins and forget to set-tris to reflect those changes.
with b) speed... standard adds a couple instructions and as I said for 99.99% of the programs you'l never notice any difference.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Fri Feb 17, 2017 2:29 am     Reply with quote

I'd perhaps be slightly lower on the percentage, but it is certainly 95%+.
Very Happy
The exceptions are generally two specific things:
1) Ultimate speed. Can be important for some things like BLDC control, or very fine timing for an external chip.
2) Mixed byte wide I/O. Things like using interrupt on change on several pins at once on a port while also wanting to write several output bits to the same port.

Historically, CCS sometimes got the settings wrong, but for the last few years, the automatic settings have been pretty faultless, so the first thing is that 'if in doubt try with this off'.
Then the second lesson is 'if using this, you need to get the settings right'.

You need to read the data sheet for the specific peripheral, and set the bits as required for the peripheral (and in the case of SPI for the direction involved).

There is also another caveat, that the settings do differ between chips. Historically on many of the older PIC's you had to set pins up to have the direction involved in the peripheral. On many later chips, you instead have to set them as inputs and the peripheral overrides this. So using manual, does make portability less.
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