Author Topic: PIC16F18325 interrupt issue  (Read 591 times)

0 Members and 1 Guest are viewing this topic.

Offline pyroesp

  • Regular Contributor
  • *
  • Posts: 170
  • Country: be
    • Nicolas Electronics
PIC16F18325 interrupt issue
« on: September 21, 2019, 11:32:52 pm »
I've read the interrupt, SPI and timer0 chapters over and over again, but I can't seem to get any interrupts to trigger.
I'm probably still missing something but I can't figure out what it is.

I've also added two 'debug' outputs:
- RA4 toggles in the main loop
- RA5 toggles in the interrupt

RA4 toggles without issue, but RA5 never changes state, which means that no interrupt is triggered.

I actually don't need the timer0, just the two SPI. That was just to test if the interrupt worked with a simple 8 bit timer, but like I said it doesn't work.


The code can be found in here : https://gist.github.com/pyroesp/b088bb76131b981d15bf9718ccc29edc
The interrupt setup starts at line 220.

More info:
 - internal 32MHz
 - 3.5VDC powered
 - SPI1 slave mode set to RC0, RC1, RC2 (SS, CLK, SDI)
 - SPI2 slave mode set to RA0, RA1, RA2 (SS, CLK, SDI)
 - SPI clock = 250kHz
 - Timer0 set to 8 bit mode : interrupt triggers when TMR0L == TMR0H
 - TMR0H set to 30; arbitrary number. I just wanted to see RA5 output toggle.


I've tried searching for interrupt example codes for the 16F18325, but I didn't find any so I couldn't compare.
I also tried the MPLAB Code Config tool but I couldn't see what the difference was between their generated code and mine.


Any help is greatly appreciated.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4784
  • Country: gb
Re: PIC16F18325 interrupt issue
« Reply #1 on: September 21, 2019, 11:55:01 pm »
I very strongly recommend that you try to code this down to basics, i.e., don’t run before you can walk.

You’re saying you can’t trigger any interrupts at all as far as I can tell.

In that case, just concentrate on getting a simple timer interrupt running, and discard everything else.

Already I think there’s a misunderstanding of how timer 0 works, as far as I am aware there is no mode where it compares TMR0H with TMR0L.

 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4784
  • Country: gb
Re: PIC16F18325 interrupt issue
« Reply #2 on: September 22, 2019, 12:37:24 am »
Here is some code that works with HFINTOSC on TMR0. Note that I had to set the T0ASYNC bit to make it work.

This was tested on a Curiosity board DM164137 with real silicon.

Code: [Select]

// PIC16F18325 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
 #pragma config FEXTOSC = OFF    // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled)
 #pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with 2x PLL (32MHz))
 #pragma config CLKOUTEN = ON    // Clock Out Enable bit (CLKOUT function is enabled; FOSC/4 clock appears at OSC2)
 #pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
 #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
 #pragma config MCLRE = ON       // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled)
 #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
 #pragma config WDTE = OFF       // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored)
 #pragma config LPBOREN = OFF    // Low-power BOR enable bit (ULPBOR disabled)
 #pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled)
 #pragma config BORV = LOW       // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V)
 #pragma config PPS1WAY = OFF    // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence))
 #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset)
 #pragma config DEBUG = OFF      // Debugger enable bit (Background debugger disabled)

// CONFIG3
 #pragma config WRT = OFF        // User NVM self-write protection bits (Write protection off)
 #pragma config LVP = ON         // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored.)

// CONFIG4
 #pragma config CP = OFF         // User NVM Program Memory Code Protection bit (User NVM code protection disabled)
 #pragma config CPD = OFF        // Data NVM Memory Code Protection bit (Data NVM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of for ON and OFF.

 <xc.h>

void __interrupt() MyISR(void)
{
    if (PIR0bits.TMR0IF)
    {
        PIR0bits.TMR0IF=0;
        LATAbits.LATA5=!LATAbits.LATA5;
    }
}

int main(void)
{
    TRISAbits.TRISA5=0;
   
    TMR0L=0;
    T0CON1bits.T0CS=0b011; // 0b011 => HFINTOSC
//    T0CON1bits.T0CS=0b010; // 0b010 => Fosc/4
    T0CON1bits.T0ASYNC=1; // 1 => not synchronised to Fosc/4
    PIE0bits.TMR0IE=1;
    PIR0bits.TMR0IF=0;
   
    INTCONbits.GIE=1;
   
    T0CON0bits.T0EN=1;
   
    while (1)
    {
        NOP();
    }
    return 0;
}

 
The following users thanked this post: pyroesp

Offline pyroesp

  • Regular Contributor
  • *
  • Posts: 170
  • Country: be
    • Nicolas Electronics
Re: PIC16F18325 interrupt issue
« Reply #3 on: September 22, 2019, 12:51:44 am »
You're correct. I don't know what I read when I saw that TMR0L is compared with TMR0H somewhere in the 8-bit mode.
The interrupt flag is also called TMR0 *overflow*... It was a long day today.
I'll try setting up the TMR0 correctly tomorrow.

Any ideas on why my SPI isn't working ?
I did measure the voltage of the different signals and IIRC they were all above the minimum VIH and below the maximum VIL, so those should be fine.
I wouldn't think 250kHz SPI is too much for the 16F18325 at 32MHz.

EDIT: Thanks for testing a program :-+ ! I'll fix the TMR0 tomorrow.
 

Offline pyroesp

  • Regular Contributor
  • *
  • Posts: 170
  • Country: be
    • Nicolas Electronics
Re: PIC16F18325 interrupt issue
« Reply #4 on: September 22, 2019, 10:54:23 am »
I changed the TMR0 interrupt to 16 bit mode, TMR0 = 0xFFF0 and set the T0ASYNC to 1 like you did Howardlong.
The interrupt on TMR0 works fine now.

I must be doing something wrong with the SPI stuff then. I'll have a read again see if I can spot something that's missing or is incorrect.

EDIT: I've updated the code with the working TMR0 overflow interrupt. Same link as before : https://gist.github.com/pyroesp/b088bb76131b981d15bf9718ccc29edc
« Last Edit: September 22, 2019, 11:23:21 am by pyroesp »
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4784
  • Country: gb
Re: PIC16F18325 interrupt issue
« Reply #5 on: September 22, 2019, 03:00:26 pm »
If you run off the Fosc/4, or a derivative of it, you don’t need to set the T0ASYNC.

I recommend that you get one SPI working by itself first, without any other code and using polling rather than interrupts.

Then you get it working with interrupts.

Then integrate it into the rest of your code.

Providing the complete code that reproduces your problem in a single bit of source code is a lot more helpful than some who provide a snippet without context, or a dozen source files created by a code generator. However, what is always helpful is stripping down the code to the absolute bare minimum to recreate and isolate the problem: if I were to attack your problem, that’s exactly what I’d be doing, and what I did for the earlier code snippet that I provided.

I don’t know what debugging tools you have, e.g., what debugger or of you have a scope. If you have a debugger that supports software breakpoints that will help, as these devices only have a single hardware breakpoint.
 

Offline pyroesp

  • Regular Contributor
  • *
  • Posts: 170
  • Country: be
    • Nicolas Electronics
Re: PIC16F18325 interrupt issue
« Reply #6 on: September 23, 2019, 02:44:00 am »
The timer0 was merely there to test the ISR, which didn't in my original post. But it works now thanks to you.

The thing is, this same code -except the timer and for the PIC SFR- works on an atmega328PB (which has dual SPI modules with interrupt).
So I know that this works, I just adapted it for the smaller and cheaper PIC16F18325.

I agree with you that I should try one SPI first, with polling method instead of interrupt.
This was also the way I made it work on the 328PB, which it turns out the voltages weren't right for logic high... Anyways

I only have a PICKit3 to program my PICs. I could try debugging with it, but I'll have to move the pins a bit as it needs the ICSP pins to be free.
I do have a DS1052E, which is how I was measuring the output of RA4 en RA5.

It's been a while since I've done debugging through the PICKit3 so I'll have to read up on that first, but it could be fun.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4784
  • Country: gb
Re: PIC16F18325 interrupt issue
« Reply #7 on: September 23, 2019, 10:05:20 am »
The code below configures SPI2 as a test polled SPI master running at 250kbps. It also configures SPI1 as an interrupt driven slave SPI, with its slave inputs attached to the master outputs by configuring the PPS appropriately. Within the ISR, it reads SPI1, and writes the 1's complement so we can see something working in the trace.

Please note that you must configure ANSEL and TRIS bits appropriately when configuring the MSSP.

RA0 PGED
RA1 PGEC
RA2 NC
RA3 /MCLR
RA4 CLKO
RA5 Debug GPIO 1 (super loop twiddle)

RC0 SCK1 & SCK2
RC1 SDI1 & SDO2
RC2 SDO1
RC3 /SS1 & /CS2
RC4 Debug GPIO 2 (=1 during ISR)
RC5 SDI2 (read but discarded)

In the timing diagram, (from an Analog Discovery 2 that I had with me during my commute this morning) note that RA4 [CLKO]
RA5 [Debug GPIO 1 (super loop twiddle)] are undersampled.

Code: [Select]

// PIC16F18325 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
 #pragma config FEXTOSC = OFF    // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled)
 #pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with 2x PLL (32MHz))
 #pragma config CLKOUTEN = ON    // Clock Out Enable bit (CLKOUT function is enabled; FOSC/4 clock appears at OSC2)
 #pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
 #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
 #pragma config MCLRE = ON       // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled)
 #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
 #pragma config WDTE = OFF       // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored)
 #pragma config LPBOREN = OFF    // Low-power BOR enable bit (ULPBOR disabled)
 #pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled)
 #pragma config BORV = LOW       // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V)
 #pragma config PPS1WAY = OFF    // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence))
 #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset)
 #pragma config DEBUG = OFF      // Debugger enable bit (Background debugger disabled)

// CONFIG3
 #pragma config WRT = OFF        // User NVM self-write protection bits (Write protection off)
 #pragma config LVP = ON         // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored.)

// CONFIG4
 #pragma config CP = OFF         // User NVM Program Memory Code Protection bit (User NVM code protection disabled)
 #pragma config CPD = OFF        // Data NVM Memory Code Protection bit (Data NVM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of for ON and OFF.

 <xc.h>
 <stdint.h>

 _XTAL_FREQ 32000000UL
 SPI2_BAUD_RATE 250000UL

void __interrupt() MyISR(void)
{
    LATCbits.LATC4=1; // Debug LED2
   
    if (PIR1bits.SSP1IF)
    {
        PIR1bits.SSP1IF=0;
        SSP1BUF=~SSP1BUF; // Read input buffer, and write the 1's complement of what's received
    }
   
    LATCbits.LATC4=0; // Debug LED2
}

void main(void)
{
    uint8_t u8Count=0; // Counter to generate test data on SPI2 master
   
    // Debug output bit
    TRISAbits.TRISA5=0; // Debug LED1
    TRISCbits.TRISC4=0; // Debug LED2
   
    //*************************
    // SPI2: set up as polled master
    SSP2ADD=(uint8_t)((_XTAL_FREQ/(4UL*SPI2_BAUD_RATE)-1)+0.5);
    SSP2STATbits.SMP=0; // 0 => Input data sampled at middle of data output time
    SSP2STATbits.CKE=1; // 1 => Transmit occurs on transition from active to Idle clock state
    SSP2CON1bits.CKP=1; // 1 => Idle state for clock is a high level
    SSP2CON1bits.SSPM=0b1010; // 0b1010 => SPI Master mode, clock = FOSC/(4 * (SSPADD+1))
   
    // SCK2
    RC0PPSbits.RC0PPS=0b11010; // 0b11010 => SCK2 (also SCK1)
    TRISCbits.TRISC0=0;
    ANSELCbits.ANSC0=0;
   
    // SDI2 (not actually used in code, data is thrown away)
    SSP2DATPPS=0b10101; // 0b10101 => RC5
    TRISCbits.TRISC5=1;
    ANSELCbits.ANSC5=0;
   
    // /CS2 (for master, we have to manually generate a chip select: /SS2 only works in slave mode)
    LATCbits.LATC3=1;
    TRISCbits.TRISC3=0;
    ANSELCbits.ANSC3=0;

    // SDO2
    RC1PPSbits.RC1PPS=0b11011; // 0b11011 => SDO2 (also SDI1)
    TRISCbits.TRISC1=0;
    ANSELCbits.ANSC1=0;
   
    //*************************
    // SPI1: set up as interrupt slave
    SSP1STATbits.SMP=0; // 0 => Input data sampled at middle of data output time
    SSP1STATbits.CKE=1; // 1 => Transmit occurs on transition from active to Idle clock state
    SSP1CON1bits.CKP=1; // 1 => Idle state for clock is a high level
    SSP1CON1bits.SSPM=0b0100; // 0100 => SPI Slave mode, clock = SCK pin, SS pin control enabled
    PIR1bits.SSP1IF=0;
    PIE1bits.SSP1IE=1;
   
    // SCK1 - already configured by SCK2
    RC0PPSbits.RC0PPS=0b11010; // 0b11010 => SCK2 (also SCK1)
//    TRISCbits.TRISC0=1; // **** NOTE: SCK1 input is on the same pin as SCK2 test output, so leave TRIS bit alone: in normal situation, SCK1 TRIS should be set TRIS=1
    ANSELCbits.ANSC0=0;

    // SDI1
    SSP1DATPPS=0b10001; // 0b10001 => RC1
//    TRISCbits.TRISC5=1; // **** NOTE: SDI1 input is on the same pin as SDO2 test output, so leave TRIS bit alone: in normal situation, SDI1 TRIS should be set TRIS=1
    ANSELCbits.ANSC1=0;

    // /SS1
    SSP1SSPPS=0b10011; // 0b010011 => RC3
//    TRISCbits.TRISC3=0; // **** NOTE: /SS1 input is on the same pin as /CS2 test output, so leave TRIS bit alone: in normal situation, /SS1 TRIS should be set TRIS=1
    ANSELCbits.ANSC3=0;

    // SDO1
    RC2PPSbits.RC2PPS=0b11001; // 0b11001 => SDO1
    TRISCbits.TRISC2=0;
    ANSELCbits.ANSC2=0;

    // Start up
    SSP1CON1bits.SSPEN=1; // 1 => Enables serial port and configures SCK, SDO, SDI and SS as the source of the serial port pins
    SSP2CON1bits.SSPEN=1; // 1 => Enables serial port and configures SCK, SDO, SDI and SS as the source of the serial port pins
   
    INTCONbits.PEIE=1;
    INTCONbits.GIE=1;

    SSP1BUF=0;
    SSP2BUF=0; // Send a dummy initial byte to get things rolling
   
    while (1)
    {
        LATAbits.LATA5=1; // Debug LED1
        LATAbits.LATA5=0;
       
        // Polled SPI2 master
        if (SSP2STATbits.BF)
        {
            LATCbits.LATC3=1; // /CS2
            SSP2BUF; // Dummy read
            LATCbits.LATC3=0; // /CS2
            SSP2BUF=u8Count++;
        }
        NOP();
    }
    return;
}

« Last Edit: September 23, 2019, 10:11:22 am by Howardlong »
 
The following users thanked this post: pyroesp

Offline pyroesp

  • Regular Contributor
  • *
  • Posts: 170
  • Country: be
    • Nicolas Electronics
Re: PIC16F18325 interrupt issue
« Reply #8 on: September 24, 2019, 08:40:21 am »
Of course, the ANSEL register!!! That's what I'm missing! I totally forgot to set it for all the MSSP pins.
I do use it on the 'debug' pins RA4 and RA5, but I never do that for all other pins, so stupid...

I never even thought of setting the SCK and SS of both SPI modules on 2 pins instead of 4 different ones. That's genius!

I'll add the ANSEL register for the I/O I'm missing and test if that works. If it does then I'll change the SCK and SS so that they only use 2 pins instead of 4.
If that doesn't work, I'll split the code in simple pieces that I can more easily debug.
I'll also try your code if mine doesn't work, but looking at how you setup SPI1 as slave the same as how I did it, I'm guessing the issue is the ANSEL register.

Thanks again for your help Howardlong

I'll keep you posted on whether or not I get it to work.


EDIT:
That logic analyzer is neat!
Have you ever tried Sigrok Pulseview? It's an open source logic analyzer which works with a ton of devices.
« Last Edit: September 24, 2019, 08:43:34 am by pyroesp »
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4784
  • Country: gb
Re: PIC16F18325 interrupt issue
« Reply #9 on: September 24, 2019, 10:02:41 am »
Regarding ANSEL: probably one of the most common fubars whether you're a noob or experienced with PICs.

I haven't tried Sigrok for some years.

The Analog Discovery (either v1 or v2) is incredibly useful when travelling as long as you can deal with and understand their limitations, such as low sample rate and small memory. There's a lot integrated into a tiny package. Best of all is that the software is very well polished compared to other USB based instruments I've used.
 
The following users thanked this post: pyroesp

Offline pyroesp

  • Regular Contributor
  • *
  • Posts: 170
  • Country: be
    • Nicolas Electronics
Re: PIC16F18325 interrupt issue
« Reply #10 on: October 01, 2019, 01:51:42 am »
Interrupt on SPI works now. Like mentioned before, it was just the ANSEL register.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf