View previous topic :: View next topic |
Author |
Message |
mquemelli
Joined: 18 Oct 2016 Posts: 9
|
Problem using SPI communication inside of interrupt TIMER0 |
Posted: Wed Feb 15, 2017 7:33 am |
|
|
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: 9246 Location: Greensville,Ontario
|
|
Posted: Wed Feb 15, 2017 8:14 am |
|
|
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: 19552
|
|
Posted: Wed Feb 15, 2017 8:35 am |
|
|
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
|
|
Posted: Wed Feb 15, 2017 9:55 am |
|
|
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: 19552
|
|
Posted: Wed Feb 15, 2017 10:13 am |
|
|
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
|
|
Posted: Wed Feb 15, 2017 6:27 pm |
|
|
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: 9246 Location: Greensville,Ontario
|
|
Posted: Wed Feb 15, 2017 6:41 pm |
|
|
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: 19552
|
|
Posted: Fri Feb 17, 2017 2:29 am |
|
|
I'd perhaps be slightly lower on the percentage, but it is certainly 95%+.
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. |
|
|
|