Microchip PIC16F1829 Deep Sleep - c

I'm struggling to get the PIC16F1829 to enter sleep mode. The unit draws around 18mA while the data sheet is quoting 20nA in deep sleep mode. Could anyone help?
According to the datasheet I have to do the following "WDT, BOR, FVR, and T1OSC
disabled, all Peripherals Inactive" which is done I think as shown below?
#include <pic16Lf1829.h>
#include <plib/adc.h>
#include <plib/pconfig.h>
#include <plib/usart.h>
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = ECL // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
int main(int argc, char** argv) {
/*******************OSCILATOR CONFIGURATION*************/
OSCCON = 0b01101000; // OSCILATOR CONTROL REGISTER 1MHz
BORCON = 0x00;
WDTCON = 0x00; // Enable watchdog timer
/*******************************************************************************/
/**********************PORT A,B,C SETUP*************************************/
ANSELB = 0b00000000; /* Enable Digital input = 0 or Analogue = 1*/
WPUB = 0b00000000; /* Enable PULL UP 1 = yes 0 - NO*/
TRISB = 0b00000000; /* Tri-state PIN*/
PORTB = 0b00000000; /* Set PORTB Logic */
WPUC = 0b00000000;
ANSELC = 0b00000000; /* Enable Digital input = 0 or Analogue = 1*/
TRISC = 0b00000000; /* Tri-state PIN*/
PORTC = 0b00000000; /* Set PORTB Logic */
WPUA = 0b00000000;
ANSELA = 0b00000000; /* Enable Digital input = 0 or Analogue = 1*/
TRISA = 0b00000000; /* Tri-state PIN*/
PORTA = 0b00000000; /* Set PORTB Logic */
IOCBP = 0b00100000; /* INTERRUPT-ON-CHANGE PORTB POSITIVE EDGE REGISTER*/
IOCBN = 0b00000000; /* INTERRUPT-ON-CHANGE PORTB NEGATIVE EDGE REGISTER*/
INTCON = 0b01011000; /* Enable int on PIN Change*/
/*******************************************************************************/
bit_set(INTCON,7); /*ENABLE GLOBAL INTERUPTS*/
ADCON0 = 0x00;
ADCON1 = 0x00;
T1CON = 0x00;
T2CON = 0x00;
FVRCON = 0x00; //FIXED VOLTAGE REFERENCE CONTROL REGISTER
CM1CON0 = 0x00;
CM1CON1 = 0x00;
CM2CON1 = 0x00;
CM2CON0 = 0x00;
PWM1CON = 0x00;
PWM2CON = 0x00;
DACCON0 = 0X00;
DACCON1 = 0X00;
T1CON = 0X00;
/********** MAIN LOOP START*******************/
for(;;) {
SLEEP();
}

This may be the result of the lack of exception handling. You enable interrupts but you have no function to catch them. If for any reason, an interrupt flag would be set, there is nothing to clear it and your pic will branch to the interrupt vector since GIE is set (even if in sleep). Since you have not specified an interrupt function, you may (depending on your compiler) end up in an un-programmed memory region executing arbitrary instructions at full speed.
Try the same code with :
--- INTCON = 0b01011000; /* Enable int on PIN Change*/
+++ INTCON = 0b00000000; /* Disable all int */

According datasheet, 18mA is too high for this mcu(~5mA # 32Mhz).
Verify that mcu pins are not shorted.
Verify that outputs voltage are currectly configured.(for exampl i2c pins should be "output high" etc')
Verify your VCC is not powering other modules.

Related

SPI Slave using PIC24FJ64GP202

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.

Gated Timer on PIC18 sets TMR3IF flag to late & with Fosc/4 it doesn't set it anyway

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.

Trying to understand Microchip PIC16LF15344 peripheral pin selection for I2C

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.

Why this simple PWM doesn't work in xc8

I know there are a lot of examples in internet, but what does need this code to work ?
frecuency oscillator = 4mhz
periode = 0.25us
duty_cicle = 250
Prescale = 16
PR2 = 124
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <pic16f88.h>
#pragma config FOSC = HS // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = ON // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
void main ()
{
while (1)
{
CCP1CON = 0x2C; /*activate PWM mode*/
PR2 = 0x7C; /*124 (DECIMAL)*/
T2CON = 0X06; /*prescale 16 */
CCPR1L = 0X3E;
}
}
I want to see :
Period of PWM = 2ms
Dutycicle = 1ms
Sincerilly
NIN
First off topic:
Don't include pic16f88.h, it's included by xc.h.
Little more off topic:
If you use a more modern part (e.g. PIC16f1619), you can use the MPLAB Code Configurator to generate the TMR2 and CCP code for you. It'll also cost less and have more flash/ram. That device is on the curiosity board ($20).
On Topic:
Your first stop is the datasheet.
The PWM section has the setup for PWM operation.
Step1:
The timer 2 takes Fosc/4 as an input, which is 1mhz in your case.
Target frequency is 500Hz. 1e6/500 = 2k.
I'd suggest a prescaler of 16, and pr value of 125. This will give you exactly 500Hz.
Step2:
We want a 50% duty cycle. CCP1L floor(125/2) = 62. CCP1X:CCP1Y = 0.5 * 4 = 2.
Step 3:
Clear the tris bit.
Step4 and 5:
Turn it on
// Step 1
TMR2ON = 0;
TOUTPS = 0;
T2CKPS = 2;
PR2 = 250U;
// Step 2
CCP1L = 62U;
CCP1X = 1;
CCP1Y = 0;
// Step 3
TRISB3 = 0;
// Step 4
TMR2ON = 1;
// Step 5
CCP1M = 0xC;
Hope that helps.
The datasheet states:
In Pulse-Width Modulation (PWM) mode, the CCP1 pin
produces up to a 10-bit resolution PWM output. Since
the CCP1 pin is multiplexed with the PORTB data latch,
the TRISB bit must be cleared to make the CCP1
pin an output.
So you must set the TRIS bit for the CCP1 pin to output:
TRISB &= ~(1 << 3); //Clear bit RB3/CCP1 in TRISB, makes PORTB3/CCP1 output.
This assumes CCPMX: CCP1 Pin Selection bit in the configuration word is clear. If set, then CCP1 is on RB0 in stead of RB3 but since I see no mention of CCPMX in your configuration pragma's i assume it is cleared.

PIC16F887 PORT won't work with XC8 C compiler

I'm pretty new to PIC programming and I'm trying to use C (compiled with Microchip's XC8 Free in MPLABX) to make a simple "Input to Output" program.
The problem I'm having is that the RA2, RA3 and RA5 input pins are just not working when programming in C.
It's probably not a hardware problem, because when programming in Ladder those pins work just fine.
I've searched around on the internet for a while and couldn't find anyone with the same problem yet.
The program I'm trying to burn onto the PIC is as follows:
#define _XTAL_FREQ 20000000
#include <xc.h>
// BEGIN CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//END CONFIG
int main()
{
TRISB = 0x00;
TRISE = 0x00;
TRISC = 0x00;
TRISD = 0xFF;
TRISA = \
_TRISA_TRISA2_MASK |\
_TRISA_TRISA3_MASK |\
_TRISA_TRISA4_MASK |\
_TRISA_TRISA5_MASK;
PORTD = 0x00;
PORTA = 0x00;
PORTB = 0x00;
PORTE = 0x00;
PORTC = 0x00;
while(1){
PORTB = PORTA;
}
return 0;
}
I do get an output on PORTB if I set RA4 to HIGH, but not for RA2, RA3 nor RA5. I believe this might be a problem with the configuration bits or something, but I'm not sure.
Hardware being used:
Microchip PIC16F887
FLEXiS Plus Board (sorry no english manual, but in page 8 and 9 there are board schematics)
Software being used:
Microchip MPLABX IDE
TinyBootloader
I think the problem is that those specific pins are also Analog Inputs for the ADC Module, you have to configure them to be digital I/O to use them. Try setting ANSEL = 0x00 at the beginning of your program.
You can see in the datasheet that the default value of ANSEL on POR is 0xFF so all analog pins are configured as analog inputs by default.
To use pins for analog input, you should set the relevant bits in both the ANSEL and TRISx registers.

Resources