I have trouble with a PIC24FJ64GP202 to work as an spi slave.
I have simplified the code to the minimum possible in order to find the problem.
In this simple code, an spi master (it is an ATSAMD51N19A) will send 0x55 to a spi slave (it is a PIC24FJ64GP202) once per second at 1MHz.
I can see the signal waveforms on the slave pins so the transmission is fine (please see the attached image but please note that the sample code does not implement the spi2 that communicates with the GLCD because this part of the code works fine and I want to target the problem: making it work as a slave SPI to enventually receive commands from another microcontroller).
The problem is with the spi slave. I can confirm that the pins receives the signal (CSn, spi1 clk, SDI but when I debug the code, the spi interrupt will not fire with the PIC24FJ64GP202 that is configured in slave mode.
Here is the pinout for the spi slave (PIC24FJ64GP202):
CSn (SS): RB2, pin 6
Spi1 clk: RB3, pin 7
SDI: RB4, pin 11
SDO: RB5, pin 14
Any idea why the interrupt will not fire and why the SPI1BUFL and SPI1BUFH are always 0 eventhough the master sends 0x55 with a 1MHz clk once per second ?
Here is the slave simplified code (in one main.c file):
// FSEC
#pragma config BWRP = OFF //Boot Segment Write-Protect bit->Boot Segment may be written
#pragma config BSS = DISABLED //Boot Segment Code-Protect Level bits->No Protection (other than BWRP)
#pragma config BSEN = OFF //Boot Segment Control bit->No Boot Segment
#pragma config GWRP = OFF //General Segment Write-Protect bit->General Segment may be written
#pragma config GSS = DISABLED //General Segment Code-Protect Level bits->No Protection (other than GWRP)
#pragma config CWRP = OFF //Configuration Segment Write-Protect bit->Configuration Segment may be written
#pragma config CSS = DISABLED //Configuration Segment Code-Protect Level bits->No Protection (other than CWRP)
#pragma config AIVTDIS = OFF //Alternate Interrupt Vector Table bit->Disabled AIVT
// FBSLIM
#pragma config BSLIM = 8191 //Boot Segment Flash Page Address Limit bits->8191
// FOSCSEL
#pragma config FNOSC = FRC //Oscillator Source Selection->FRC
#pragma config PLLMODE = PLL96DIV2 //PLL Mode Selection->96 MHz PLL. Oscillator input is divided by 2 (8 MHz input)
#pragma config IESO = OFF //Two-speed Oscillator Start-up Enable bit->Start up with user-selected oscillator source
// FOSC
#pragma config POSCMD = NONE //Primary Oscillator Mode Select bits->Primary Oscillator disabled
#pragma config OSCIOFCN = OFF //OSC2 Pin Function bit->OSC2 is clock output
#pragma config SOSCSEL = OFF //SOSC Selection Configuration bits->Digital (SCLKI) mode
#pragma config PLLSS = PLL_FRC //PLL Secondary Selection Configuration bit->PLL is fed by the on-chip Fast RC (FRC) oscillator
#pragma config IOL1WAY = ON //Peripheral pin select configuration bit->Allow only one reconfiguration
#pragma config FCKSM = CSECMD //Clock Switching Mode bits->Clock switching is enabled,Fail-safe Clock Monitor is disabled
// FWDT
#pragma config WDTPS = PS32768 //Watchdog Timer Postscaler bits->1:32768
#pragma config FWPSA = PR128 //Watchdog Timer Prescaler bit->1:128
#pragma config FWDTEN = OFF //Watchdog Timer Enable bits->WDT and SWDTEN disabled
#pragma config WINDIS = OFF //Watchdog Timer Window Enable bit->Watchdog Timer in Non-Window mode
#pragma config WDTWIN = WIN25 //Watchdog Timer Window Select bits->WDT Window is 25% of WDT period
#pragma config WDTCMX = WDTCLK //WDT MUX Source Select bits->WDT clock source is determined by the WDTCLK Configuration bits
#pragma config WDTCLK = LPRC //WDT Clock Source Select bits->WDT uses LPRC
// FPOR
#pragma config BOREN = ON //Brown Out Enable bit->Brown-out Reset is Enabled
#pragma config LPREGEN = OFF //Low power regulator control->Low Voltage and Low Power Regulator are not available
#pragma config LPBOREN = ENABLE //Downside Voltage Protection Enable bit->Low Power BOR is enabled and active when main BOR is inactive
// FICD
#pragma config ICS = PGD1 //ICD Communication Channel Select bits->Communicate on PGEC1 and PGED1
#pragma config JTAGEN = OFF //JTAG Enable bit->JTAG is disabled
// FDMTIVTL
#pragma config DMTIVTL = 0 //Deadman Timer Interval Low Word->0
// FDMTIVTH
#pragma config DMTIVTH = 0 //Deadman Timer Interval High Word->0
// FDMTCNTL
#pragma config DMTCNTL = 0 //Deadman Timer Instruction Count Low Word->0
// FDMTCNTH
#pragma config DMTCNTH = 0 //Deadman Timer Instruction Count High Word->0
// FMDT
#pragma config DMTDIS = OFF //Deadman Timer Enable Bit->Dead Man Timer is Disabled and can be enabled by software
// FDEVOPT1
#pragma config ALTCMP1 = DISABLE //Alternate Comparator 1 Input Enable bit->C1INC is on RB13 and C3INC is on RA0
#pragma config TMPRPIN = OFF //Tamper Pin Enable bit->TMPRN pin function is disabled
#pragma config SOSCHP = ON //SOSC High Power Enable bit (valid only when SOSCSEL = 1->Enable SOSC high power mode (default)
#pragma config ALTI2C1 = ALTI2C1_OFF //Alternate I2C pin Location->I2C1 Pin mapped to SDA1/SCL1 pins
#pragma config ALTCMP2 = DISABLE //Alternate Comparator 2 Input Enable bit->C2INC is on RA4 and C2IND is on RB4
#pragma config SMB3EN = SMBUS3 //SM Bus Enable->SMBus 3.0 input levels
#ifndef FCY
#define FCY 16000000UL
#endif
#include <xc.h>
#include <libpic30.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static void CLK_Initialize(void);
static void PPS_Initialize(void);
static void PORT_Initialize(void);
static void SPI1_Initialize(void);
static void INTERRUPT_Initialize(void);
static uint8_t SPI1_exchangeByte(uint8_t data);
static void MSSP1_InterruptHandler(void);
volatile uint8_t sPI_receivedData = 0; /* Data that will be received on the spi bus of the slave */
volatile uint8_t writeData = 1; /* Data that will be transmitted (don't care) */
#define SPI_SS_TRIS TRISBbits.TRISB2
#define SPI_SS_PORT PORTBbits.RB2
#define lcdBackLight_RA2_SetHigh() (_LATA2 = 1)
#define lcdBackLight_RA2_SetLow() (_LATA2 = 0)
#define lcdBackLight_RA2_Toggle() (_LATA2 ^= 1)
#define status0_LED_SetHigh() (_LATB7 = 1)
#define status0_LED_SetLow() (_LATB7 = 0)
#define status0_LED_Toggle() (_LATB7 ^= 1)
#define lcd_FrontPanel_CSn_SetHigh() (_LATB2 = 1)
#define lcd_FrontPanel_CSn_SetLow() (_LATB2 = 0)
#define lcd_FrontPanel_CSn_Toggle() (_LATB2 ^= 1)
#define lcd_FrontPanel_CSn_GetValue() _RB2
#define spi1clk1_GetValue() _RB3
#define spi1SI_GetValue() _RB4
#define status0_SetHigh() (_LATB7 = 1)
#define status0_SetLow() (_LATB7 = 0)
#define status0_Toggle() (_LATB7 ^= 1)
static void CLK_Initialize(void)
{
// CPDIV 1:1; PLLEN disabled; DOZE 1:8; RCDIV FRC; DOZEN disabled; ROI disabled;
CLKDIV = 0x3000;
// STOR disabled; STORPOL Interrupt when STOR is 1; STSIDL disabled; STLPOL Interrupt when STLOCK is 1; STLOCK disabled; STSRC SOSC; STEN disabled; TUN Center frequency;
OSCTUN = 0x00;
// ROEN disabled; ROSWEN disabled; ROSEL FOSC; ROOUT disabled; ROSIDL disabled; ROSLP disabled;
REFOCONL = 0x00;
// RODIV 0;
REFOCONH = 0x00;
// DIV 0;
OSCDIV = 0x00;
// TRIM 0;
OSCFDIV = 0x00;
// AD1MD enabled; T3MD enabled; T1MD enabled; U2MD enabled; T2MD enabled; U1MD enabled; SPI2MD enabled; SPI1MD enabled; I2C1MD enabled;
PMD1 = 0x00;
// RTCCMD enabled; CMPMD enabled; CRCMD enabled; I2C2MD enabled;
PMD3 = 0x00;
// REFOMD enabled; HLVDMD enabled;
PMD4 = 0x00;
// CCP2MD enabled; CCP1MD enabled; CCP4MD enabled; CCP3MD enabled; CCP5MD enabled;
PMD5 = 0x00;
// DMA0MD enabled;
PMD7 = 0x00;
// DMTMD enabled; CLC3MD enabled; CLC4MD enabled; CLC1MD enabled; CLC2MD enabled;
PMD8 = 0x00;
// CF no clock failure; NOSC FRCPLL; SOSCEN disabled; POSCEN disabled; CLKLOCK unlocked; OSWEN Switch is Complete; IOLOCK not-active;
__builtin_write_OSCCONH((uint8_t) (0x01));
__builtin_write_OSCCONL((uint8_t) (0x01));
// Wait for Clock switch to occur
while (OSCCONbits.OSWEN != 0);
while (OSCCONbits.LOCK != 1);
}
static void PPS_Initialize(void)
{
__builtin_write_OSCCONL(OSCCON & 0xbf); // unlock PPS
//SPI1 PPS configuration
RPINR21bits.SS1R = 0x0002; //RB2->SPI1:SSn
RPINR20bits.SCK1R = 0x0003; //RB3->SPI1:SCK1IN
RPINR20bits.SDI1R = 0x0004; //RB4->SPI1:SDI1
RPOR2bits.RP5R = 0x0007; //RB5->SPI1:SDO1
__builtin_write_OSCCONL(OSCCON | 0x40); // lock PPS
}
static void PORT_Initialize(void)
{
TRISAbits.TRISA2 = 0x0000;//lcd backlight
TRISBbits.TRISB7 = 0x0000;//status0
TRISBbits.TRISB5 = 0x0000;//spi1_MISO
TRISBbits.TRISB4 = 0x0001;//spi1_MOSI
TRISBbits.TRISB3 = 0x0001;//spi1_SCK
TRISBbits.TRISB2 = 0x0001;//lcd_FrontPanel_CSn
/****************************************************************************
* Setting the Analog/Digital Configuration SFR(s)
***************************************************************************/
ANSA = 0x0000;//all digital IO
ANSB = 0x0000;
}
static void SPI1_Initialize(void)
{
IEC0bits.SPI1IE = 0; // disable spi1 interrupt
//config SPI1
SPI1CON1bits.SPIEN = 0; // disable SPI port
SPI1BUFL = 0; // clear SPI buffer Low bits
SPI1BUFH = 0; // clear SPI buffer High bits
SPI1CON1Lbits.ENHBUF = 0; // Clear the ENHBUF bit (SPIxCON1L[0]) if using Standard Buffer mode
IFS0bits.SPI1IF = 0; // clear interrupt flag
// SPI1: SPI 1
// Priority: 1
IPC2bits.SPI1IP = 1; // interrupt priority set to the highest
IEC0bits.SPI1IE = 1; // enable spi1 interrupt
SPI_SS_PORT = 1; //
SPI_SS_TRIS = 1; // set SS as input
IFS0bits.SPI1IF = 0; // clear interrupt flag
IEC0bits.SPI1IE = 1; // enable spi1 interrupt
SPI1STATLbits.SPIROV = 0; // Clear the SPIROV bit
//desired settings
//Write the desired settings to the SPI1CON1L register with MSTEN (SPI1CON1L[5]) = 0.
SPI1CON1bits.MSTEN = 0; // 1 = Master mode; 0 = Slave mode
SPI1CON1Lbits.SPISIDL = 0; // Continue module operation in Idle mode
SPI1CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
SPI1CON1bits.MODE16 = 0; // set in 16-bit mode, clear in 8-bit mode
SPI1CON1bits.SMP = 0; // SMP must be cleared when SPIx is used in Slave mode
SPI1CON1bits.CKP = 1; // CKP and CKE is subject to change ...
SPI1CON1bits.CKE = 0; // ... based on your communication mode.
SPI1CON1bits.SSEN = 1; // SSx pin is used for Slave mode
SPI1CON1Lbits.ENHBUF = 0;
//SPI1CON2 = 0; // non-framed mode
SPI1CON1bits.SPIEN = 1; // enable SPI port, clear status
}
static void INTERRUPT_Initialize(void)
{
INTCON2bits.GIE = 1; /* Enable Global Interrupts */
}
uint32_t gCounter;
int main(void)
{
CLK_Initialize();
PPS_Initialize();
PORT_Initialize();
SPI1_Initialize();
INTERRUPT_Initialize();
gCounter = 0;
status0_LED_SetHigh();
while(1)
{
//just to watch CSn signal coming once per second on the spi slave bus
if(!lcd_FrontPanel_CSn_GetValue())//!cs_1 && clk_1)
{
status0_Toggle();
lcdBackLight_RA2_SetHigh();
gCounter++;
__delay_ms(100);
}
else //if(!cs_1)
{
lcdBackLight_RA2_SetLow();
}
if(sPI_receivedData > 1)
status0_Toggle();
}
}
static uint8_t SPI1_exchangeByte(uint8_t data)
{
SPI1BUFL = data;
while(!IFS0bits.SPI1IF) /* Wait until data is exchanged */
{
;
}
IFS0bits.SPI1IF = 0;
return SPI1BUFL;
}
static void MSSP1_InterruptHandler(void)
{
sPI_receivedData = SPI1_exchangeByte(writeData);
}
//spi1 interrupt never fired. Why? ...SPI1 pins are receiving the data and the clk once per second but interrupt will not fire... Why?
void __attribute__((__interrupt__,__auto_psv__)) _SPI1Interrupt(void)//void __attribute__ (( interrupt, no_auto_psv )) _SPI1Interrupt ( void ) //void __interrupt() INTERRUPT_InterruptManager(void)
{
if(IEC0bits.SPI1IE == 1 && IFS0bits.SPI1IF == 1)
{
MSSP1_InterruptHandler();
}
}
Did not find why the spi slave configuration doesnt work with the PIC24FJ64GP202. We did try a development board Explorer 16 with a PIC24FJ128GA010 and the SPI slave works perfectly with the same above code (except the pinout).
... Still dont know why the PIC24FJ64GP202 gives this issue...
So,
To save the hardware we have for our product, it was possible to switch and use the spi CS pin as an Rx UART instead. The uart works perfectly for our requirements... We were lucky to have that pin configurable in UART on both the ATSAMD51N19 in TX and the PIC24F64GP202 in RX.
I am beginner exploring PIC32MK1024MCM064 timers. Just want to write simple code with self triggering timer and some main program in the background. So I achieved my code to get into the ISR part, but the code gets stuck in the ISR after first time interrupt event. The code does not come back to the main loop with blinking leds. I investigated the datasheet quite well, but besides clearing the interrupt flag, I don`t know what to do else. I really thank you in advance for any help provided
// DEVCFG3
#pragma config USERID = 0xFFFF // Enter Hexadecimal value (Enter Hexadecimal value)
#pragma config PWMLOCK = OFF // PWM IOxCON lock (PWM IOxCON register writes accesses are not locked or protected)
#pragma config FUSBIDIO2 = ON // USB2 USBID Selection (USBID pin is controlled by the USB2 module)
#pragma config FVBUSIO2 = ON // USB2 VBUSON Selection bit (VBUSON pin is controlled by the USB2 module)
#pragma config PGL1WAY = OFF // Permission Group Lock One Way Configuration bit (Allow multiple reconfigurations)
#pragma config PMDL1WAY = OFF // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
#pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration (Allow multiple reconfigurations)
#pragma config FUSBIDIO1 = ON // USB1 USBID Selection (USBID pin is controlled by the USB1 module)
#pragma config FVBUSIO1 = ON // USB2 VBUSON Selection bit (VBUSON pin is controlled by the USB1 module)
// DEVCFG2
#pragma config FPLLIDIV = DIV_1 // System PLL Input Divider (1x Divider)
#pragma config FPLLRNG = RANGE_BYPASS // System PLL Input Range (Bypass)
#pragma config FPLLICLK = PLL_FRC // System PLL Input Clock Selection (FRC is input to the System PLL)
#pragma config FPLLMULT = MUL_2 // System PLL Multiplier (PLL Multiply by 1)
#pragma config FPLLODIV = DIV_2 // System PLL Output Clock Divider (2x Divider)
#pragma config BORSEL = HIGH // Brown-out trip voltage (BOR trip voltage 2.1v (Non-OPAMP deviced operation))
#pragma config UPLLEN = OFF // USB PLL Enable (USB PLL Disabled)
// DEVCFG1
#pragma config FNOSC = FRC // Oscillator Selection Bits (Internal Fast RC (FRC))
#pragma config DMTINTV = WIN_0 // DMT Count Window Interval (Window/Interval value is zero)
#pragma config FSOSCEN = OFF // Secondary Oscillator Enable (Disable Secondary Oscillator)
#pragma config IESO = OFF // Internal/External Switch Over (Disabled)
#pragma config POSCMOD = OFF // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor Selection (Clock Switch Disabled, FSCM Disabled)
#pragma config WDTPS = PS1 // Watchdog Timer Postscaler (1:1)
#pragma config WDTSPGM = STOP // Watchdog Timer Stop During Flash Programming (WDT stops during Flash programming)
#pragma config WINDIS = NORMAL // Watchdog Timer Window Mode (Watchdog Timer is in non-Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT Disabled)
#pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window size is 25%)
#pragma config DMTCNT = DMT31 // Deadman Timer Count Selection (2^31 (2147483648))
#pragma config FDMTEN = OFF // Deadman Timer Enable (Deadman Timer is disabled)
// DEVCFG0
#pragma config DEBUG = OFF // Background Debugger Enable (Debugger is disabled)
#pragma config JTAGEN = OFF // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx3 // ICE/ICD Comm Channel Select (Communicate on PGEC3/PGED3)
#pragma config TRCEN = OFF // Trace Enable (Trace features in the CPU are disabled)
#pragma config BOOTISA = MIPS32 // Boot ISA Selection (Boot code and Exception code is MIPS32)
#pragma config FECCCON = ECC_DECC_DISABLE_ECCON_WRITABLE// Dynamic Flash ECC Configuration Bits (ECC and Dynamic ECC are disabled (ECCCON<1:0> bits are writable))
#pragma config FSLEEP = OFF // Flash Sleep Mode (Flash is powered down when the device is in Sleep mode)
#pragma config DBGPER = PG_ALL // Debug Mode CPU Access Permission (Allow CPU access to all permission regions)
#pragma config SMCLR = MCLR_NORM // Soft Master Clear Enable (MCLR pin generates a normal system Reset)
#pragma config SOSCGAIN = G3 // Secondary Oscillator Gain Control bits (Gain is G3)
#pragma config SOSCBOOST = ON // Secondary Oscillator Boost Kick Start Enable bit (Boost the kick start of the oscillator)
#pragma config POSCGAIN = G3 // Primary Oscillator Coarse Gain Control bits (Gain Level 3 (highest))
#pragma config POSCBOOST = ON // Primary Oscillator Boost Kick Start Enable bit (Boost the kick start of the oscillator)
#pragma config POSCFGAIN = G3 // Primary Oscillator Fine Gain Control bits (Gain is G3)
#pragma config POSCAGCDLY = AGCRNG_x_25ms// AGC Gain Search Step Settling Time Control (Settling time = 25ms x AGCRNG)
#pragma config POSCAGCRNG = ONE_X // AGC Lock Range bit (Range 1x)
#pragma config POSCAGC = Automatic // Primary Oscillator Gain Control bit (Automatic Gain Control for Oscillator)
#pragma config EJTAGBEN = NORMAL // EJTAG Boot Enable (Normal EJTAG functionality)
// DEVCP
#pragma config CP = OFF // Code Protect (Protection Disabled)
// SEQ
#pragma config TSEQ = 0x0 // Boot Flash True Sequence Number (Enter Hexadecimal value)
#pragma config CSEQ = 0xFFFF // Boot Flash Complement Sequence Number (Enter Hexadecimal value)
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include <xc.h>
#include <toolchain_specifics.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "stdio.h"
#include <sys/attribs.h>
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#define CPU_CLOCK_FREQUENCY 8000000
#define _CP0_GET_COUNT() _mfc0 (_CP0_COUNT, _CP0_COUNT_SELECT)
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void delay_ms ( uint32_t delay_ms)
{
uint32_t startCount, endCount;
endCount=((CPU_CLOCK_FREQUENCY/1000)*delay_ms)/2;
startCount=_CP0_GET_COUNT();
while((_CP0_GET_COUNT()-startCount)<endCount);
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Timer2_setup(void){
PB2DIVbits.ON = 0b0; //PB2CLK is disabled
PB2DIVbits.PBDIVRDY = 0b1; //Enabling the PBDIV configuration
PB2DIVbits.PBDIV = 0b0000000; //PBCLKx is SYSCLK divided by 128
PB2DIVbits.PBDIVRDY = 0b0; //Disabling the PBDIV configuration
PB2DIVbits.ON = 0b1; //PB2CLK is enabled
//----------------------------------------------------
T2CONbits.ON = 0b0; //Timer2 is disabled
T2CONbits.TCS = 0b0; //Internal peripheral clock
T2CONbits.T32 = 0b1; //Timer2 is set to 32 bits
T2CONbits.TCKPS = 0b101; //1:256 prescale value
T2CONbits.SIDL = 0b1; //Timer2 does not work in idle mode
TMR2 = 0x0; //Clear counter
PR2 = 124999U; //Timer2 period is set to 1000 milliseconds
//----------------------------------------------------
//Interrupt setup
IEC0bits.T2IE = 0b1; //Enable timer interrupt
IPC2bits.T2IP = 0b001; //Interrupt priority set to 1
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int main ( void )
{
TRISAbits.TRISA7 = 0;
LATAbits.LATA7 = 0;
TRISBbits.TRISB14 = 0;
LATBbits.LATB14 = 0;
TRISBbits.TRISB15 = 0;
LATBbits.LATB15 = 0;
Timer2_setup();
__builtin_enable_interrupts(); // VERY IMPORTANT Built in macro function to globally enable interrupts
T2CONbits.ON = 0b1; //Timer2 is enabled
while (1)
{
LATBbits.LATB14 = 1;
delay_ms(300);
LATBbits.LATB14 = 0;
LATBbits.LATB15 = 1;
delay_ms(300);
LATBbits.LATB15 = 0;
}
return (EXIT_FAILURE);
}
//INTERRUPTS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void __ISR( _TIMER_2_VECTOR, IPL1SRS) Timer2_Handler (void){
T2CONbits.ON = 0b0; //Timer2 is disabled
TMR2 = 0x0; //Clear counter
LATAbits.LATA7 = 1;
delay_ms(300); //Interrupt indicator
LATAbits.LATA7 = 0;
IFS0bits.T2IF = 0b0; //Clear input change interrupt
T2CONbits.ON = 0b1; //Timer2 is enabled
}
You most definitely shouldn't call delay_ms() in your interrupt handler. I'm fairly sure that this is the reason of your problem. IRQ handlers should be as quick as possible.
Check out https://www.aidanmocke.com/blog/2018/11/15/timers/. This whole blog is great for learning firmware development on PIC32.
I have already spent several nights debugging gated timer on PIC18F26K80. I use MPLAB v4.15 and XC8 v2.32. I want to run a long period timer, so I chose Timer 3 gated by Timer 4. I've read Microchip's documentation and tried to find answers anywhere, but I cannot understand:
Why it doesn't set TMR3IF flag (and doesn't fire appropriate interruption) using Fosc/4 as a clock source of Timer 3 (so I use Fosc with prescale 1:4 - it works, but... why Fosc/4 doesn't?)
Why TMR3IF flag fires in TMR3 state 0x0001? It should fire from 0xFFFF to 0x0000 and with PR4 = 0x63 there is no need to step over 0x0000 so fast.
So these 2 points are the most important points, there are some other miracles, but, if you could, help me with these.
/*
* Test file for Gated timer
*/
// PIC18F26K80 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1L
#pragma config RETEN = OFF // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = DIG // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = INTIO2 // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = OFF // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3 // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)
// CONFIG2H
#pragma config WDTEN = SWDTDIS // Watchdog Timer (WDT enabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576 // Watchdog Postscaler (1:1048576)
// CONFIG3H
#pragma config CANMX = PORTB // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7 // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K // Boot Block Size (2K word Boot Block size)
// CONFIG5L
#pragma config CP0 = OFF // Code Protect 00800-03FFF (Disabled)
#pragma config CP1 = OFF // Code Protect 04000-07FFF (Disabled)
#pragma config CP2 = OFF // Code Protect 08000-0BFFF (Disabled)
#pragma config CP3 = OFF // Code Protect 0C000-0FFFF (Disabled)
// CONFIG5H
#pragma config CPB = OFF // Code Protect Boot (Disabled)
#pragma config CPD = OFF // Data EE Read Protect (Disabled)
// CONFIG6L
#pragma config WRT0 = OFF // Table Write Protect 00800-03FFF (Disabled)
#pragma config WRT1 = OFF // Table Write Protect 04000-07FFF (Disabled)
#pragma config WRT2 = OFF // Table Write Protect 08000-0BFFF (Disabled)
#pragma config WRT3 = OFF // Table Write Protect 0C000-0FFFF (Disabled)
// CONFIG6H
#pragma config WRTC = OFF // Config. Write Protect (Disabled)
#pragma config WRTB = OFF // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF // Data EE Write Protect (Disabled)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protect 00800-03FFF (Disabled)
#pragma config EBTR1 = OFF // Table Read Protect 04000-07FFF (Disabled)
#pragma config EBTR2 = OFF // Table Read Protect 08000-0BFFF (Disabled)
#pragma config EBTR3 = OFF // Table Read Protect 0C000-0FFFF (Disabled)
// CONFIG7H
#pragma config EBTRB = OFF // Table Read Protect Boot (Disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#include <stdint.h>
uint8_t tmr3Lprev = 0x00u;
void interrupt ISR(void){
if(TMR3IF){
if(TMR3L == 0x00u){ //after TMR3IF fires, TMR3L should be 0 (if PR4 is > cca 0x20)
asm("BTG LATA, 2, 0"); //toggles with an output
}else{
LATAbits.LATA6 = 1; // a failure flag
}
asm("BTG LATA, 1, 0"); //toggles with an output
TMR3IF = 0;
}
if(TMR4IF){
if(TMR3L == ++tmr3Lprev){ //TMR3L should increment on every T4 rollover
asm("BTG LATA, 0, 0"); //toggles with an output
}else{
LATAbits.LATA5 = 1; // a failure flag
}
TMR4IF = 0;
}
return;
}
void main(void) {
//Clock setting (clock for system and all modules)
OSCCONbits.IRCF = 0b111;
OSCTUNEbits.PLLEN = 1; //turn on 4x Phase Lock Loop = 64MHz Clock
//sets ports to output
TRISA = 0x00; //A vse prepnout na vystup
LATA = 0x00;
//Timer4 initialization
T4CONbits.T4OUTPS = 0; //postscale, I don't know why, but doesen't effect length of T4 rollover
T4CONbits.T4CKPS1 = 1; //I dont know why, but T4CKPS = 0x11 doesnt set T4CKPS1
PR4 = 0x63; //loop periode
T4CONbits.TMR4ON = 1; //1 = Timer 4 Enabled
//Timer3 initialization
T3CONbits.TMR3CS = 0b01; //Clock source, 1 = system clock = Fosc; 0 = instruction clock = Fosc/4
T3CONbits.T3CKPS = 0b10; // 0b11 = 1:8 Prescale value; 0b10 = 1:4 Prescale value; 0b01 = 1:2 Prescale value; 0b00 = 1:1 Prescale value
T3CONbits.SOSCEN = 0;
T3CONbits.RD16 = 1; //16bits wide register
T3CONbits.TMR3ON = 1; //1 = Timer 3 Enabled
T3GCONbits.TMR3GE = 1; //Timer 3 is gated
T3GCONbits.T3GPOL = 1; //high/low level of timer4 enables Timer3
T3GCONbits.T3GTM = 0; //Toggle mode disabled
T3GCONbits.T3GSPM = 0; //Single pulse mode disabled
T3GCONbits.T3GSS = 0x01; //TMR4 as a source
WRITETIMER3(0x0000ul);
TMR4 = 0x00;
//interrupts handling
PIE2bits.TMR3IE = 1;
PIE4bits.TMR4IE = 1;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
//the infinite loop
while(1){
}
}
I have spent plenty of time solving this problem (even there: https://www.microchip.com/forums/m1211315.aspx) and my conclusion is, that it is most probably a HW bug. So Timers 1 and 3 with gated control (from Timer 2/4) works properly as a timer (their registers TMR1/3H/L increment well), but they fail in triggering interrupts and setting appropriate PIR flags.
So my resolution for another applications is:
let's use Timers 1/3 as counters of TMR2/4 rollovers (and make a 24bit wide timer), it works well and is useful;
but do not use any (including CCP) ISR function (or PIR values) rising from Timer 1/3 with gated control from Timer 2/4. I simply use ISR rising from Timer 2/4 and test Timer 1/3 state by SW.
I familiarising myself with MPLAB X IDE and staring development with C using a Microchip PIC 12F617.
I have a simple program (copied from elsewhere) to flash a LED: on for 1 second then off for 1 second. It all works but I my calculation of the delay does not match 1 second. Anybody able to tell me where I am going wrong?
Internal osc is selected # 8 MHz
clock to TMR2 is FOSC / 4 is 2 MHz
PR2 default to 255 so interrupt at 2 MHz / 255 is 7843 Hz
TMR2 prescale = 1; postscale set to 16; is 490 Hz
Loop counts 675 is 0.726 Hz so LED should be on/off for 1.38 seconds, yet it isn't
Taking into account time for executing instructions the led on/off should be even longer.
what am I missing?
/*
* File: main.c
* Author: user2439830
* Target: PIC12F617
* Compiler: XC8 v2.05
*
* PIC12F617
* +------v------+
* 5v0 ->:1 VDD VSS 8:<- GND
* <>:2 GP5 GP0 7:<> PGD
* <>:3 GP4 GP1 6:<> PGC
* VPP ->:4 GP3 GP2 5:<>
* +-------------+
* DIP-8
*
* Created on May 20, 2020, 5:51 PM
*/
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/AN3/T1G/OSC2/CLKOUT, I/O function on RA5/T1CKI/OSC1/CLKIN)
#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select bit (MCLR pin is MCLR function and weak internal pull-up is enabled)
#pragma config CP = OFF // Code Protection bit (Program memory is not code protected)
#pragma config IOSCFS = 8MHZ // Internal Oscillator Frequency Select (8 MHz)
#pragma config BOREN = ON // Brown-out Reset Selection bits (BOR enabled)
#pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off)
#include <xc.h>
void t2delay( void );
void main(void)
{
// Note: TRISIO = TRISA; IO direction register
TRISIO = 0; // 0 set corresponding pin in GPIO to output
// 76543210
T2CON = 0b01111000; // postscale=16, prescale=1, timer off
T2CON |= ( 1 << 2 ); //timer2 on TMR2ON set to 1
while (1)
{
// Note: GPIO = PORTA
GPIO = 255;
t2delay();
GPIO = 0;
t2delay();
}
return;
}
// TMR2IF set to when when TMR2 == PR2 (set to 255 on reset)
void t2delay( void )
{
unsigned int i;
for( i = 0; i < 675; i++)
{
while( !TMR2IF );
TMR2IF = 0;
}
}
Your main bug is the watchdog timer is on and your code does not reset it.
I have been reviewing the Microchip PIC16LF15344 datasheet for peripheral pin selection, and either I am reading it incorrectly or it appears to have errors and inconsistencies in the document. I would like to know if anyone else has used this device and can confirm my interpretation.
I'm trying to write code for a PIC16LF15344 to make use of the I2C interface. I have managed to write I2C code for a PIC16LF1822 that works fine, but I have so far been unable to get this to work on the PIC16LF15344, and there is some confusing documentation in the data sheet that I would like to get cleared up.
Here is a reference to the datasheet.
The pinout descriptions for the PIC16LF15344 shows that the I2C SDA function can be allocated to RC1 or RB6. Likewise, I2C SCL may be allocated to RC0 or RB4. But there is a note in Section 15.3 Bidirectional Pins as follows.
The I2C SCLx and SDAx functions can be remapped through PPS. However, only the RB1, RB2, RC3, and RC4 pints have the I2C and SMBus specific input buffers implemented (I2C mode disables INLVL and sets thresholds that are specific for I2C). If the SCLx or SDAx functions are mapped to some other pin (other than RB1, RB2, RC3, or RC4), the general purpose TTL or ST input buffers (as configured based on INLVL register setting) will be used instead. In most applications, it is therefore recommended only to map the SCLx and SDAx pin functions to the RB1, RB2, RC3 or RC4 pins.
The problem is not only does the note appear to conflict with the descriptions in the pin allocation tables, it also references pins RB1 and RB2, which don't appear anywhere in the pin allocation tables, i.e., they don't appear to exist for this PIC. I see similar footnote references to RB1 and RB2, but they are not documented anywhere in the body of the document or the tables.
Certainly this must be a documentation error, but I can find no current errata on the PIC16LF15324/44 datasheet to correct this. Am I reading this right?
I have tried configuring SCL and SDA with PPS to pins RC0 and RC1, since that is how they are wired on my PCB, but I can't get the I2C working yet using essentially the same software that I was using for the PIC16LF1822. The PPS default for EUSART TX2 and RX2 are RC0 and RC1. Does that mean I need to use TX2CKPPS and RX2DTPPS to move the EUSART assignments elsewhere before using SSP1CLKPPS and SSP1DATPPS to assign SCL and SDA to RC0 and RC1?
I will be investigating other potential problems with my PCB, but I want to get this straightened out before I submit another PCB for fab. I need to make some changes anyway, so I might just connect SCL and SDA to their PPS defaults in the next version and try again.
Here is the initialization code:
OSCFRQbits.HFFRQ = 0b011; // Set internal HF oscillator frequency to 8 MHz
WPUA = 0b00111111; // Enable all weak pull-up resistors on port A
WPUB = 0b11110000; // Enable all weak pull-up resistors on port B
WPUC = 0b11111100; // Enable all weak pull-up resistors on port C except
// RC0 and RC1 to be used as I2C SCL and SDA
TRISA = 0b00110000; // Set RA4 and RA5 as inputs
ANSELA = 0b00110000; // Set RA4 and RA5 to analog
TRISB = 0b00110000; // Set RB6 and RB7 as inputs
ANSELB = 0b11000000; // Set RB6 and RB7 as analog
TRISC = 0b11111011; // Set RC0, RC1, RC3, RC4, RC5, RC6, and RC7 as inputs
ANSELC = 0b11111000; // Set RC3, RC4, RC5, RC6, and RC7 as analog
TX2CKPPS = 0b01100; // Use RB4 for TX2
RX2DTPPS = 0b01110; // Use RB6 for RX2
SSP1CLKPPS = 0b10000; // Use RC0 as SCL
SSP1DATPPS = 0b10001; // Use RC1 as SDA
SSP1CON1 = 0b00100110; // SSPEN enabled, WCOL no collision, SSPOV no overflow,
// CKP low hold, SSPM I2C slave 7-bit
SSP1CON2 = 0b00000000; // ACKSTAT received, RCEN disabled, RSEN disabled,
// ACKEN disabled, ACKDT acknowledge, SEN disabled,
// GCEN disabled, PEN disabled
SSP1CON3 = 0b00000000; // BOEN disabled, AHEN disabled, SBCDE disabled,
// SDAHT 100 ns hold, ACKTIM ackseq, DHEN disabled,
// PCIE disabled, SCIE disabled
SSP1STAT = 0x00;
SSP1BUF = 0x00;
SSP1MSK = 0xff;
SSP1ADD = I2C_SLAVE_ADDR << 1;
PIR3bits.SSP1IF = 0; // Clear the SSP Interrupt flag
PIE3bits.SSP1IE = 1; // Enable SSP Interrupts
INTCONbits.GIE = 1; // Enable global interrupts
INTCONbits.PEIE = 1; // Enable peripheral interrupts
You likely have several issues to deal with.
All of the default I2C pins also have analog functionality too. Be sure that the ANSB or ANSC bits that are associated with the I2C pins are setup for digital operation.
While the power on reset selects the data sheet defaults for the I2C input pin assignments the I2C outputs by default are not assigned to any GPIO pin. You will need to place the I2C outputs for SCL and SDA in the correct PPS mapping registers.
Note that regardless of the I2C master or slave implementation both the input and output functions should be mapped to the same pin.
It would help to edit your question and post the code that you use to initialize the I2C pins and PPS mapping registers.
/*
* File: main.c
* PIC16LF15354
* +-------------:_:-------------+
* 10K Pull-Up -> 1 : RE3/MCLR ANB7/RX2/PGD/RB7 : 28 <>
* <> 2 : RA0/ANA0 ANB6/TX2/PGC/RB6 : 27 <> RX2
* <> 3 : RA1/ANA1 ANB5/RB5 : 26 <>
* <> 4 : RA2/ANA2 ANB4/RB4 : 25 <> TX2
* <> 5 : RA3/ANA3 ANB3/RB3 : 24 <>
* <> 6 : RA4/ANA4 ANB2/SDA2/RB2 : 23 <>
* <> 7 : RA5/ANA5 ANB1/SCL2/RB1 : 22 <>
* GND -> 8 : VSS ANB0/RB0 : 21 <>
* <> 9 : RA7/OSC1/ANA7 VDD : 20 <- 3v3
* <> 10 : RA6/OSC2/ANA6 VSS : 19 <- GND
* SCL1 <> 11 : RC0/ANC0 ANC7/RX1/RC7 : 18 <>
* SDA1 <> 12 : RC1/ANC1 ANC6/TX1/RC6 : 17 <>
* <> 13 : RC2/ANC2 ANC5/RC5 : 16 <>
* <> 14 : RC3/SCL1/ANC3 ANC4/SDA1/RC4 : 15 <>
* +-----------------------------:
* DIP-28
*
* Created on January 4, 2019, 6:20 PM
*/
// PIC16LF15354 Configuration Bit Settings
#pragma config FEXTOSC = OFF // External Oscillator mode selection bits (Oscillator not enabled)
#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with OSCFRQ= 32 MHz and CDIV = 1:1)
#pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on 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 bit (FSCM timer disabled)
#pragma config MCLRE = ON // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#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 = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
#pragma config ZCD = OFF // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = OFF // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = SWDTEN // WDT operating mode (WDT enabled/disabled by SWDTEN bit in WDTCON0)
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC // WDT input clock selector (Software Control)
#pragma config BBSIZE = BB512 // Boot Block Size Selection bits (512 words boot block size)
#pragma config BBEN = OFF // Boot Block Enable bit (Boot Block disabled)
#pragma config SAFEN = OFF // SAF Enable bit (SAF disabled)
#pragma config WRTAPP = OFF // Application Block Write Protection bit (Application Block not write protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block not write protected)
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration Register not write protected)
#pragma config WRTSAF = OFF // Storage Area Flash Write Protection bit (SAF not write protected)
#pragma config LVP = OFF // Low Voltage Programming Enable bit (High Voltage on MCLR/Vpp must be used for programming)
#pragma config CP = OFF // UserNVM Program memory code protection bit (UserNVM code protection disabled)
#include <xc.h>
#define I2C_SLAVE_ADDR 0x00
void main(void)
{
WPUA = 0b00111111; // Enable all weak pull-up resistors on port A
WPUB = 0b11110000; // Enable all weak pull-up resistors on port B
WPUC = 0b11111100; // Enable all weak pull-up resistors on port C except
// RC0 and RC1 to be used as I2C SCL and SDA
TRISA = 0b00110000; // Set RA4 and RA5 as inputs
ANSELA = 0b00110000; // Set RA4 and RA5 to analog
TRISB = 0b00110000; // Set RB6 and RB7 as inputs
ANSELB = 0b11000000; // Set RB6 and RB7 as analog
TRISC = 0b11111011; // Set RC0, RC1, RC3, RC4, RC5, RC6, and RC7 as inputs
ANSELC = 0b11111000; // Set RC3, RC4, RC5, RC6, and RC7 as analog
#ifdef WRONG_WAY_TO_DO_PPS
TX2CKPPS = 0b01100; // Use RB4 for TX2
RX2DTPPS = 0b01110; // Use RB6 for RX2
SSP1CLKPPS = 0b10000; // Use RC0 as SCL
SSP1DATPPS = 0b10001; // Use RC1 as SDA
#else
RB4PPS = 0x11; // Assign TX2 output to RB4
RX2DTPPS = 0x0E; // Assign RB6 to RX2 input
RC0PPS = 0x15; // Assign SCL1 output to RC0
SSP1CLKPPS = 0x10; // Assign RC0 to SCL1 input
RC1PPS = 0x16; // Assign SDA1 output to RC1
SSP1DATPPS = 0x11; // Assign RC1 to SDA1 input
#endif
SSP1CON1 = 0b00100110; // SSPEN enabled, WCOL no collision, SSPOV no overflow,
// CKP low hold, SSPM I2C slave 7-bit
SSP1CON2 = 0b00000000; // ACKSTAT received, RCEN disabled, RSEN disabled,
// ACKEN disabled, ACKDT acknowledge, SEN disabled,
// GCEN disabled, PEN disabled
SSP1CON3 = 0b00000000; // BOEN disabled, AHEN disabled, SBCDE disabled,
// SDAHT 100 ns hold, ACKTIM ackseq, DHEN disabled,
// PCIE disabled, SCIE disabled
SSP1STAT = 0x00;
SSP1BUF = 0x00;
SSP1MSK = 0xff;
SSP1ADD = I2C_SLAVE_ADDR << 1;
PIR3bits.SSP1IF = 0; // Clear the SSP Interrupt flag
PIE3bits.SSP1IE = 1; // Enable SSP Interrupts
INTCONbits.GIE = 1; // Enable global interrupts
INTCONbits.PEIE = 1; // Enable peripheral interrupts
/*
* Embedded code never returns from main
*/
for(;;)
{
}
}
The PPS is setup correctly but I do not know if the I2C initialization code is right.