PIC16F18325 interrupt issue - Page 1
Forum section: electronics / general

author: pyroesp
author_rank: Regular Contributor
timestamp: September 21, 2019, 11:32:52 pm
content: 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 interruptRA4 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/b088bb76131b981d15bf9718ccc29edcThe 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.

author: Howardlong
author_rank: Super Contributor
timestamp: September 21, 2019, 11:55:01 pm
content: 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.

author: Howardlong
author_rank: Super Contributor
timestamp: September 22, 2019, 12:37:24 am
content: 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:// 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/4T0CON1bits.T0ASYNC=1; // 1 => not synchronised to Fosc/4PIE0bits.TMR0IE=1;PIR0bits.TMR0IF=0;INTCONbits.GIE=1;T0CON0bits.T0EN=1;while (1){NOP();}return 0;}

author: pyroesp
author_rank: Regular Contributor
timestamp: September 22, 2019, 12:51:44 am
content: 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 VIHand 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.

author: pyroesp
author_rank: Regular Contributor
timestamp: September 22, 2019, 10:54:23 am
content: 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

author: Howardlong
author_rank: Super Contributor
timestamp: September 22, 2019, 03:00:26 pm
content: 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.

author: pyroesp
author_rank: Regular Contributor
timestamp: September 23, 2019, 02:44:00 am
content: 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... AnywaysI 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.

author: Howardlong
author_rank: Super Contributor
timestamp: September 23, 2019, 10:05:20 am
content: 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 PGEDRA1 PGECRA2 NCRA3 /MCLRRA4 CLKORA5 Debug GPIO 1 (super loop twiddle)RC0 SCK1 & SCK2RC1 SDI1 & SDO2RC2 SDO1RC3 /SS1 & /CS2RC4 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 RA5 [Debug GPIO 1 (super loop twiddle)] are undersampled.Code:// 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 32000000ULSPI2_BAUD_RATE 250000ULvoid __interrupt() MyISR(void){LATCbits.LATC4=1; // Debug LED2if (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 bitTRISAbits.TRISA5=0; // Debug LED1TRISCbits.TRISC4=0; // Debug LED2//*************************// SPI2: set up as polled masterSSP2ADD=(uint8_t)((_XTAL_FREQ/(4UL*SPI2_BAUD_RATE)-1)+0.5);SSP2STATbits.SMP=0; // 0 => Input data sampled at middle of data output timeSSP2STATbits.CKE=1; // 1 => Transmit occurs on transition from active to Idle clock stateSSP2CON1bits.CKP=1; // 1 => Idle state for clock is a high levelSSP2CON1bits.SSPM=0b1010; // 0b1010 => SPI Master mode, clock = FOSC/(4 * (SSPADD+1))// SCK2RC0PPSbits.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 => RC5TRISCbits.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;// SDO2RC1PPSbits.RC1PPS=0b11011; // 0b11011 => SDO2 (also SDI1)TRISCbits.TRISC1=0;ANSELCbits.ANSC1=0;//*************************// SPI1: set up as interrupt slaveSSP1STATbits.SMP=0; // 0 => Input data sampled at middle of data output timeSSP1STATbits.CKE=1; // 1 => Transmit occurs on transition from active to Idle clock stateSSP1CON1bits.CKP=1; // 1 => Idle state for clock is a high levelSSP1CON1bits.SSPM=0b0100; // 0100 => SPI Slave mode, clock = SCK pin, SS pin control enabledPIR1bits.SSP1IF=0;PIE1bits.SSP1IE=1;// SCK1 - already configured by SCK2RC0PPSbits.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=1ANSELCbits.ANSC0=0;// SDI1SSP1DATPPS=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=1ANSELCbits.ANSC1=0;// /SS1SSP1SSPPS=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=1ANSELCbits.ANSC3=0;// SDO1RC2PPSbits.RC2PPS=0b11001; // 0b11001 => SDO1TRISCbits.TRISC2=0;ANSELCbits.ANSC2=0;// Start upSSP1CON1bits.SSPEN=1; // 1 => Enables serial port and configures SCK, SDO, SDI and SS as the source of the serial port pinsSSP2CON1bits.SSPEN=1; // 1 => Enables serial port and configures SCK, SDO, SDI and SS as the source of the serial port pinsINTCONbits.PEIE=1;INTCONbits.GIE=1;SSP1BUF=0;SSP2BUF=0; // Send a dummy initial byte to get things rollingwhile (1){LATAbits.LATA5=1; // Debug LED1LATAbits.LATA5=0;// Polled SPI2 masterif (SSP2STATbits.BF){LATCbits.LATC3=1; // /CS2SSP2BUF; // Dummy readLATCbits.LATC3=0; // /CS2SSP2BUF=u8Count++;}NOP();}return;}

author: pyroesp
author_rank: Regular Contributor
timestamp: September 24, 2019, 08:40:21 am
content: 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 HowardlongI'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.

author: Howardlong
author_rank: Super Contributor
timestamp: September 24, 2019, 10:02:41 am
content: 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.

author: pyroesp
author_rank: Regular Contributor
timestamp: October 01, 2019, 01:51:42 am
content: Interrupt on SPI works now. Like mentioned before, it was just the ANSEL register.