• AVR Freaks

AnsweredNewbie, need help with I2C on PIC16F15376

Author
T1000Android
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2020/09/14 10:54:09
  • Location: 0
  • Status: offline
2020/09/15 08:22:18 (permalink)
0

Newbie, need help with I2C on PIC16F15376

Hello all.
 
I am new (1 month) to programming any sort of microcontroller. I need help with setting up and transmitting one byte (for starters) through I2C on the PIC16F15376. I am not new to electronics, just to microcontrollers, but after 3 weeks I can't seem to get the MSSP1 module to do anything: no start condition, no byte transmission, no nothing. Both lines (SDA and SCL) are permanently held high. I have used both external pull-ups and the internal ones (WPU) and I have tried transmitting with no slave and with a slave attached but the oscilloscope still doesn't register any pulses.
I am starting to think that maybe I got a bad batch of PICs or something. I would appreciate if you would paste your own code in your posts.
 
Thanks a bunch.
 
// PIC16F15376 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#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 = 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 = ON // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)

// CONFIG2
#pragma config MCLRE = ON // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config LPBOREN = ON // Low-Power BOR enable bit (ULPBOR enabled)
#pragma config BOREN = ON // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
#pragma config BORV = HI // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) is set to 2.7V)
#pragma config ZCD = ON // Zero-cross detect disable (Zero-cross detect circuit is always enabled)
#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)

// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = ON // WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)
#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)

// CONFIG4
#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 = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)

// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit (UserNVM code protection disabled)

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

#include <xc.h>

#define _XTAL_FREQ 32000000

void led(){
    TRISD2 = 0;
    if(SSP1CON1bits.WCOL == 1){
        LATD2 = 1;
        __delay_ms(100);
        LATD2 = 0;
    }
}

void i2c_wait(){
    while((SSP1STAT & 0b00000100) || (SSP1CON2 & 0b00011111));
}

void i2c_init(const unsigned long int freq){
    SSP1CON1 = 0b00101000;
    SSP1CON2 = 0b00000000;
    SSP1ADD = (_XTAL_FREQ / (freq * 4)) - 1;
    SSP1STAT = 0b10000000;
    TRISC3 = 1;
    TRISC4 = 1;
}

void i2c_start(){
    i2c_wait();
    SSP1CON2bits.SEN = 1;
}

void i2c_stop(){
    i2c_wait();
    SSP1CON2bits.PEN = 1;
}

void i2c_send(unsigned int data){
    i2c_wait();
    SSP1BUF = data;
}
    
void main(void) {

    //OSCCON2 = 0b01100011; // prescaler and postscaler selection (postscaler does not affect CLKOUT) (reg on page 136)
    //OSCFRQ = 0b00000011; // HFINTOSC frequency selection (reg on page 140)
    
    /*
    SSP1CON1bits.WCOL = 1;
    SSP1CON1bits.SSPOV = 1;
    SSP1CON1bits.SSPEN = 1;
    SSP1CON1bits.CKP = 1;
    SSP1CON1bits.SSPM = 1;
     *
    SSP1CON1bits.SSPM0 = 1;
    SSP1CON1bits.SSPM1 = 1;
    SSP1CON1bits.SSPM2 = 1;
    SSP1CON1bits.SSPM3 = 1;
     *
    SSP1CON2bits.GCEN = 1;
    SSP1CON2bits.ACKSTAT = 1;
    SSP1CON2bits.ACKDT = 1;
    SSP1CON2bits.ACKEN = 1;
    SSP1CON2bits.RCEN = 1;
    SSP1CON2bits.PEN = 1;
    SSP1CON2bits.RSEN = 1;
    SSP1CON2bits.SEN = 1;
    
    SSP1CON3bits.ACKTIM = 1;
    SSP1CON3bits.PCIE = 1;
    SSP1CON3bits.SCIE = 1;
    SSP1CON3bits.BOEN = 1;
    SSP1CON3bits.SDAHT = 1;
    SSP1CON3bits.SBCDE = 1;
    SSP1CON3bits.AHEN = 1;
    SSP1CON3bits.DHEN = 1;
    
    SSP1STATbits.SMP = 1;
    SSP1STATbits.CKE = 1;
    
    SSP1ADD = (_XTAL_FREQ / (100000 * 4)) - 1;
    
    SSP1BUF = 0b11111111;

    //set i2c inputs
    TRISC3 = 1;
    TRISC4 = 1;
    SSP1CLKPPS = 0x13;
    SSP1DATPPS = 0x14;
    
    //set i2c outputs
    RC3PPS = 0x15;
    RC4PPS = 0x16;*/
    
    SSP1CLKPPS = 0x13;
    SSP1DATPPS = 0x14;
    
    RC3PPS = 0x15;
    RC4PPS = 0x16;
    
    i2c_init(100000);
    while(1){
        __delay_ms(1000);
        led();
        i2c_start();
        i2c_send(0xFF);
        i2c_stop();
    }
}

 
#1
ric
Super Member
  • Total Posts : 28337
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Newbie, need help with I2C on PIC16F15376 2020/09/15 13:38:08 (permalink) ☼ Best Answerby T1000Android 2020/09/17 07:26:05
+2 (2)
A trap that catches almost all first time PIC users is, analog capable pins power up in analog mode, and cannot be used for digital input until switched to digital mode.
You are using RC3 and RC4 for SCL and SDA. Both those pins are analog capable, so you have to write to ANSELC to switch them to digital.
 
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#2
Howard Long
Super Member
  • Total Posts : 811
  • Reward points : 0
  • Joined: 2005/04/04 08:50:32
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/15 14:20:38 (permalink)
-1 (1)
ric
A trap that catches almost all first time PIC users is, analog capable pins power up in analog mode, and cannot be used for digital input until switched to digital mode.
You are using RC3 and RC4 for SCL and SDA. Both those pins are analog capable, so you have to write to ANSELC to switch them to digital.
 

... still happens to some of us oldies as well, especially when transplanting our own boilerplate code.
 
#3
T1000Android
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2020/09/14 10:54:09
  • Location: 0
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/16 06:07:18 (permalink)
0
Thanks for the answers but I have already tried clearing ANSELC3 and ANSELC4 and it still doesn't work. Could you please take a look at the config registers for MSSP1 (MSSP1CON1, MSSP1CON2, MSSP1CON3, MSSP1STAT etc). Aside from the ANSEL, have I set up the inputs and outputs correctly? Have I configured the MSSP correctly?
 
Thanks a lot.
#4
Howard Long
Super Member
  • Total Posts : 811
  • Reward points : 0
  • Joined: 2005/04/04 08:50:32
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/16 09:35:48 (permalink)
0
Try this, run on a PIC16F15375 (same as your PIC, but with less memory).
 

 
// PIC16F15376 Configuration Bit Settings
 
// 'C' source line config statements
 
// CONFIG1
#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 = 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 = ON // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)
 
// CONFIG2
#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 PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config LPBOREN = ON // Low-Power BOR enable bit (ULPBOR enabled)
#pragma config BOREN = ON // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
#pragma config BORV = HI // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) is set to 2.7V)
#pragma config ZCD = ON // Zero-cross detect disable (Zero-cross detect circuit is always enabled)
#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)
 
// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
//#pragma config WDTE = ON // WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)
#pragma config WDTE = OFF // WDT operating mode (WDT Disabled, SWDTEN is ignored)
#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)
 
// CONFIG4
#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 = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)
 
// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit (UserNVM code protection disabled)
 
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
 
#include <xc.h>
 
#define _XTAL_FREQ 32000000
 
void led(){
TRISD2 = 0;
if(SSP1CON1bits.WCOL == 1){
LATD2 = 1;
__delay_ms(100);
LATD2 = 0;
}
}
 
void i2c_wait(){
while((SSP1STAT & 0b00000100) || (SSP1CON2 & 0b00011111));
}
 
void i2c_init(const unsigned long int freq){
SSP1CON1 = 0b00101000;
SSP1CON2 = 0b00000000;
SSP1ADD = (_XTAL_FREQ / (freq * 4)) - 1;
SSP1STAT = 0b10000000;
TRISC3 = 1;
TRISC4 = 1;
}
 
void i2c_start(){
i2c_wait();
SSP1CON2bits.SEN = 1;
}
 
void i2c_stop(){
i2c_wait();
SSP1CON2bits.PEN = 1;
}
 
void i2c_send(unsigned int data){
i2c_wait();
SSP1BUF = data;
}

void main(void)
{
SSP1ADD = (_XTAL_FREQ / (100000 * 4)) - 1;
 
SSP1STATbits.SMP = 1; // 1 => Slew rate control disabled for Standard Speed mode (100 kHz and 1 MHz)
SSP1CON1bits.SSPM = 0b1000; // 0b1000 => I2C Master mode, clock = FOSC / (4 * (SSPxADD+1))
SSP1CON1bits.SSPEN = 1;

//set i2c inputs
TRISC3 = 1;
TRISC4 = 1;
 
SSP1CLKPPS = 0x13;
SSP1DATPPS = 0x14;

//set i2c outputs
RC3PPS = 0x15;
RC4PPS = 0x16;

SSP1CLKPPS = 0x13;
SSP1DATPPS = 0x14;

RC3PPS = 0x15;
RC4PPS = 0x16;

ANSELCbits.ANSC3=0; // *** HL 20200916
ANSELCbits.ANSC4=0; // *** HL 20200916

i2c_init(100000);
while(1){
__delay_ms(1000);
led();
i2c_start();
i2c_send(0xFF);
i2c_stop();
}
}
 

post edited by Howard Long - 2020/09/16 09:37:15
#5
sirhC_sirhC
Starting Member
  • Total Posts : 57
  • Reward points : 0
  • Joined: 2011/06/22 11:57:51
  • Location: Chicago
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/16 10:20:26 (permalink)
+2 (2)
Try using the MCC to configure the device.
Not that you cant do it manually, but its error prone without experience.
With the MCC you cant mistake the pins, cant blow the config, and you get something that works like InitI2C, and SendI2C() to test with.  
 
About the bad batch of PICs, as my personal motto "It's never the PIC's fault, its ALWAYS yours"  Years of practice. :-)
#6
Howard Long
Super Member
  • Total Posts : 811
  • Reward points : 0
  • Joined: 2005/04/04 08:50:32
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/16 11:41:46 (permalink)
+3 (3)
My advice is very definitely not to use MCC. It’s bug ridden, generates inefficient bloatware, and, as it’s machine generated code, it is very difficult to maintain and debug. It’s little more than a crutch that might, if you’re lucky, get you to a blinky, but much more than that is opening up a can of worms.

I admire the OP for NOT using MCC.
#7
T1000Android
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2020/09/14 10:54:09
  • Location: 0
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/17 07:38:22 (permalink)
0
ric
A trap that catches almost all first time PIC users is, analog capable pins power up in analog mode, and cannot be used for digital input until switched to digital mode.
You are using RC3 and RC4 for SCL and SDA. Both those pins are analog capable, so you have to write to ANSELC to switch them to digital.
 

 
After reconfiguring the setup registers for the MSSP module it finally worked. Thanks a lot. I have been struggling with this module for a month now.
 
I owe you a beer :)


Howard Long
My advice is very definitely not to use MCC. It’s bug ridden, generates inefficient bloatware, and, as it’s machine generated code, it is very difficult to maintain and debug. It’s little more than a crutch that might, if you’re lucky, get you to a blinky, but much more than that is opening up a can of worms.

I admire the OP for NOT using MCC.


I hear you. For some reason, I hate it. Tried using it a few times (including on the MSSP module), but after seeing the snake pit of code it generated.... no thanks.
 
So finally, I am attaching the code that works:
 


// PIC16F15376 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#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 = 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 = ON // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)

// CONFIG2
#pragma config MCLRE = ON // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config LPBOREN = ON // Low-Power BOR enable bit (ULPBOR enabled)
#pragma config BOREN = ON // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
#pragma config BORV = HI // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) is set to 2.7V)
#pragma config ZCD = ON // Zero-cross detect disable (Zero-cross detect circuit is always enabled)
#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)

// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = ON // WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)
#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)

// CONFIG4
#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 = ON // Storage Area Flash Write Protection bit (SAF not write protected)
#pragma config LVP = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)

// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit (UserNVM code protection disabled)

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

#include <xc.h>

#define _XTAL_FREQ 32000000

// EXTERNAL PULL-UPS MUST BE USED AS WEAK PULL-UPS DO NOT WORK IF PINS ARE CONFIGURED AS INPUTS

void led(){
    TRISD2 = 0;
    if(SSP1STATbits.BF == 1){
        LATD2 = 1;
        __delay_ms(50);
        LATD2 = 0;
        __delay_ms(50);
    }
}

void i2c_wait(){
    while((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));
}

void i2c_init(const unsigned long int freq){
    SSP1CLKPPS = 0x13;
    SSP1DATPPS = 0x14;
    RC3PPS = 0x15;
    RC4PPS = 0x16;
    TRISC3 = 1;
    TRISC4 = 1;
    ANSC3 = 0;
    ANSC4 = 0;
    SSP1CON1 = 0b00101000;
    SSP1CON2 = 0b00000000;
    SSP1ADD = (_XTAL_FREQ / (freq * 4)) - 1;
    SSP1STAT = 0b10000000;
    
}

void i2c_start(){
    i2c_wait();
    SSP1CON2bits.SEN = 1;
}

void i2c_stop(){
    i2c_wait();
    SSP1CON2bits.PEN = 1;
}

void i2c_send(unsigned int data){
    i2c_wait();
    SSP1BUF = data;
}
    
void main(void) {

    //OSCCON2 = 0b01100011; // prescaler and postscaler selection (postscaler does not affect CLKOUT) (reg on page 136)
    //OSCFRQ = 0b00000011; // HFINTOSC frequency selection (reg on page 140)
    
    /*
    SSP1CON1bits.WCOL = 1;
    SSP1CON1bits.SSPOV = 1;
    SSP1CON1bits.SSPEN = 1;
    SSP1CON1bits.CKP = 1;
    SSP1CON1bits.SSPM = 1;
     *
    SSP1CON1bits.SSPM0 = 1;
    SSP1CON1bits.SSPM1 = 1;
    SSP1CON1bits.SSPM2 = 1;
    SSP1CON1bits.SSPM3 = 1;
     *
    SSP1CON2bits.GCEN = 1;
    SSP1CON2bits.ACKSTAT = 1;
    SSP1CON2bits.ACKDT = 1;
    SSP1CON2bits.ACKEN = 1;
    SSP1CON2bits.RCEN = 1;
    SSP1CON2bits.PEN = 1;
    SSP1CON2bits.RSEN = 1;
    SSP1CON2bits.SEN = 1;
    
    SSP1CON3bits.ACKTIM = 1;
    SSP1CON3bits.PCIE = 1;
    SSP1CON3bits.SCIE = 1;
    SSP1CON3bits.BOEN = 1;
    SSP1CON3bits.SDAHT = 1;
    SSP1CON3bits.SBCDE = 1;
    SSP1CON3bits.AHEN = 1;
    SSP1CON3bits.DHEN = 1;
    
    SSP1STATbits.SMP = 1;
    SSP1STATbits.CKE = 1;
    
    SSP1ADD = (_XTAL_FREQ / (100000 * 4)) - 1;
    
    SSP1BUF = 0b11111111;

    //set i2c inputs
    TRISC3 = 1;
    TRISC4 = 1;
    SSP1CLKPPS = 0x13;
    SSP1DATPPS = 0x14;
    
    //set i2c outputs
    RC3PPS = 0x15;
    RC4PPS = 0x16;*/
    
    i2c_init(100000);
    while(1){
        __delay_ms(10);
        led();
        i2c_start();
        i2c_send(0b10101010);
        i2c_stop();
    }
}



 
 
#8
Howard Long
Super Member
  • Total Posts : 811
  • Reward points : 0
  • Joined: 2005/04/04 08:50:32
  • Status: offline
Re: Newbie, need help with I2C on PIC16F15376 2020/09/17 07:47:34 (permalink)
0
My personal preference is to use the bit fields with a comment on each non-obvious one, rather than writing the whole register in one go. In some cases you may need to set other bit fields first anyway before turning on the ON bit field (MCC has been known to fail this way).
 
That way, when you go back to look at your code a week or a month or a year later, you won't have to disassemble your settings again.
#9
Jump to:
© 2020 APG vNext Commercial Version 4.5