// PIC18 in C - Versione 0.2 - aprile 2016 // Copyright (c) 2016, Vincenzo Villa // Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported. // Creative Commons | Attribution-Share Alike 3.0 Unported // https://www.vincenzov.net/tutorial/PIC18/I2C-slave.htm // PIC18: I2C slave // PIC18F25K50 / MPLAB IDE 3.26 / XC8 1.37 #include // CONFIG1L #pragma config PLLSEL = PLL3X // PLL Selection (3x clock multiplier) #pragma config CFGPLLEN = OFF // PLL Enable Configuration bit (PLL Disabled (firmware controlled)) #pragma config CPUDIV = NOCLKDIV// CPU System Clock Postscaler (CPU uses system clock (no divide)) #pragma config LS48MHZ = SYS24X4// Low Speed USB mode with 48 MHz system clock (System clock at 24 MHz, USB clock divider is set to 4) // CONFIG1H #pragma config FOSC = INTOSCIO // Oscillator Selection (Internal oscillator) #pragma config PCLKEN = ON // Primary Oscillator Shutdown (Primary oscillator enabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover (Oscillator Switchover mode disabled) // CONFIG2L #pragma config nPWRTEN = OFF // Power-up Timer Enable (Power up timer disabled) #pragma config BOREN = SBORDIS // Brown-out Reset Enable (BOR enabled in hardware (SBOREN is ignored)) #pragma config BORV = 190 // Brown-out Reset Voltage (BOR set to 1.9V nominal) #pragma config nLPBOR = OFF // Low-Power Brown-out Reset (Low-Power Brown-out Reset disabled) // CONFIG2H #pragma config WDTEN = SWON // Watchdog Timer Enable bits (WDT controlled by firmware (SWDTEN enabled)) #pragma config WDTPS = 32768 // Watchdog Timer Postscaler (1:32768) // CONFIG3H #pragma config CCP2MX = RC1 // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1) #pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<5:0> pins are configured as analog input channels on Reset) #pragma config T3CMX = RC0 // Timer3 Clock Input MUX bit (T3CKI function is on RC0) #pragma config SDOMX = RB3 // SDO Output MUX bit (SDO function is on RB3) #pragma config MCLRE = ON // Master Clear Reset Pin Enable (MCLR pin enabled; RE3 input disabled) // CONFIG4L #pragma config STVREN = ON // Stack Full/Underflow Reset (Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled) #pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port Enable (ICPORT disabled) - MANUAL ADD - Bug? #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled) // CONFIG5L #pragma config CP0 = OFF // Block 0 Code Protect (Block 0 is not code-protected) #pragma config CP1 = OFF // Block 1 Code Protect (Block 1 is not code-protected) #pragma config CP2 = OFF // Block 2 Code Protect (Block 2 is not code-protected) #pragma config CP3 = OFF // Block 3 Code Protect (Block 3 is not code-protected) // CONFIG5H #pragma config CPB = OFF // Boot Block Code Protect (Boot block is not code-protected) #pragma config CPD = OFF // Data EEPROM Code Protect (Data EEPROM is not code-protected) // CONFIG6L #pragma config WRT0 = OFF // Block 0 Write Protect (Block 0 (0800-1FFFh) is not write-protected) #pragma config WRT1 = OFF // Block 1 Write Protect (Block 1 (2000-3FFFh) is not write-protected) #pragma config WRT2 = OFF // Block 2 Write Protect (Block 2 (04000-5FFFh) is not write-protected) #pragma config WRT3 = OFF // Block 3 Write Protect (Block 3 (06000-7FFFh) is not write-protected) // CONFIG6H #pragma config WRTC = OFF // Configuration Registers Write Protect (Configuration registers (300000-3000FFh) are not write-protected) #pragma config WRTB = OFF // Boot Block Write Protect (Boot block (0000-7FFh) is not write-protected) #pragma config WRTD = OFF // Data EEPROM Write Protect (Data EEPROM is not write-protected) // CONFIG7L #pragma config EBTR0 = OFF // Block 0 Table Read Protect (Block 0 is not protected from table reads executed in other blocks) #pragma config EBTR1 = OFF // Block 1 Table Read Protect (Block 1 is not protected from table reads executed in other blocks) #pragma config EBTR2 = OFF // Block 2 Table Read Protect (Block 2 is not protected from table reads executed in other blocks) #pragma config EBTR3 = OFF // Block 3 Table Read Protect (Block 3 is not protected from table reads executed in other blocks) // CONFIG7H #pragma config EBTRB = OFF // Boot Block Table Read Protect (Boot block is not protected from table reads executed in other blocks) #define I2C_ADDR 3 // I2C slave address void main(void) { // OSCCONbits.IRCF = 0b111; // 16 Mhz clock (internal clock in configurations bits) // OSCCON2bits.PLLEN = 1; // PLL enabled (16 x 3 = 48 MHz - See configurations bits) TRISA = 0x00; // Set PORTA as output LATA = 0x55; // Some LED ON, some Off TRISBbits.RB0 = 1; // Set PORTB RB0 and RBI as Digital Inputs TRISBbits.RB1 = 1; ANSELBbits.ANSB0 = 0; ANSELBbits.ANSB1 = 0; SSPCON1bits.SSPM = 0b0110; // I2C Slave mode, 7-bit address SSPCON1bits.CKP = 1; // Enable (release) clock SSPCON1bits.SSPEN = 1; // Enables the serial port and configures the SDA and SCL pins SSPCON2bits.SEN = 1; // Clock stretching is enabled for both transmit and receive SSP1ADD = I2C_ADDR << 1; // Set I2C slave address SSPSTATbits.SMP = 0; // Slew rate control disabled for Standard Speed mode RCONbits.IPEN = 1; // Enable priority levels on interrupts (global)) IPR1bits.SSPIP = 1; // MSSP Interrupt Priority set High PIE1bits.SSPIE = 1; // Enable the MSSP interrupt PMD1bits.MSSPMD = 0; // MSSP is enabled, clock source is connected, module draws digital power ei(); // Enable interrupt (only high priority) while (1); // Do nothing, forever } void interrupt __high_priority MyIsr(void) // High Priority Interrupt Service Routine { static unsigned char i2c_counter; unsigned char i2c_data; if (PIE1bits.SSPIE && PIR1bits.SSPIF) { // Interrupt from MSSP i2c_data = SSPBUF; // Read SSPBUF to clear BF if (SSP1STATbits.R_nW) { // Master is doing a read command if ((SSP1STATbits.D_nA) && (SSP1CON2bits.ACKSTAT)) { // The last byte received or transmitted was data AND // Acknowledge was not received from master // No more data requested from master // (do nothing here...) } else { // Master require a byte: put it into buffer SSPBUF = i2c_counter++; } } else // Master is doing a write command if (!SSP1STATbits.D_nA) { // Received I2C address... Prepare to receive data // (do nothing here...) } else { // i2c_data contains valid data LATA = i2c_data; // Send master data to port A LEDs } PIR1bits.SSPIF = 0; // Clear the slave interrupt flag SSP1CON1bits.CKP = 1; // release SCL } }