PIC16 MSSP I2C dead stuck at 5V - Page 1
Forum section: electronics / general

author: ilyus
author_rank: Newbie
timestamp: June 10, 2020, 09:04:10 am
content: Good day everyone. I'm pretty new to PICs and I'm trying to implement hardware I2C to communicate with...well, anything. I can't get my SDA/SCL lines do anything at all. I've spent the last 2 weeks in datasheets, I seem to understand stuff there, I've read through many examples, I've read about I2C protocol and its specs, gathered all information I can, yet I can't initiate communication.Relevant stuff: PIC16F18326http://ww1.microchip.com/downloads/en/devicedoc/40001839b.pdfhere's the datasheet. Using internal 32MHz clock. I can blink LED with correct delays, so the chip's running. It has MSSP I2C pins RC0 and RC1. Debugging LED on RC2.I use PICkit 4 with MPLAB X 5.40 and XC8 2.20 on Windows 10.Tools: multimeter, oscilloscope.Problem: I've tried to implement I2C with polling (haven't had experience with PIC interrupts, just read a few articles and watched a pair of vids on them, I could use some hand-in-hand explanation once maybe, although I kinda get how it works). So yeah, the I2C lines are stuck at 5V, and I loop forever in polling function. Pull-ups were 10k, now 2k2, no difference.I've posted on several forums and got different advice like turn off ADC or manually link peripheral to pins (internet examples, including youtube, run without those pieces of code just fine, but I added the code - who knows). And I was advised to use interrupts, which I would happily do, if I knew how, but first I just want to see me send just a single byte of info. I will have no problem writing a driver for whatever I2C device I will talk to, a little research is not a problem (actually, the biggest fun for me). I just can't communicate at the moment and I'm really badly stuck. I also have PIC16F877A lying around, and I couldn't make it talk on I2C either, but I guess if I run one, I will run another one, after all, it's about logic and algorithm.Anyway, here is the code:Code:// PIC16F18326 Configuration Bit Settings// 'C' source line config statements// CONFIG1#pragma config FEXTOSC = OFF // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled)#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with 2x PLL (32MHz))#pragma config CLKOUTEN = 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 = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)// CONFIG2#pragma config MCLRE = ON // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled)#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config WDTE = OFF // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored)#pragma config LPBOREN = OFF // Low-power BOR enable bit (ULPBOR disabled)#pragma config BOREN = ON // Brown-out Reset Enable bits (Brown-out Reset enabled, SBOREN bit ignored)#pragma config BORV = LOW // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V)#pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset)#pragma config DEBUG = OFF // Debugger enable bit (Background debugger disabled)// CONFIG3#pragma config WRT = OFF // User NVM self-write protection bits (Write protection off)#pragma config LVP = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored.)// CONFIG4#pragma config CP = OFF // User NVM Program Memory Code Protection bit (User NVM code protection disabled)#pragma config CPD = OFF // Data NVM Memory Code Protection bit (Data NVM code protection disabled)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <htc.h>#include <stdio.h>#include <stdint.h>#define _XTAL_FREQ 32000000void i2c_is_idle(void){while(!PIR1bits.SSP1IF){//};PIR1bits.SSP1IF = 0; // clear flag}void i2c_start(void){i2c_is_idle();SSP1CON2bits.SEN = 1; // Initiate START cyclewhile(SSP1CON2bits.SEN);}void i2c_rep_start(void){i2c_is_idle();SSPCON2bits.RSEN = 1;while(SSP1CON2bits.RSEN);}void i2c_stop(void){i2c_is_idle();SSPCON2bits.PEN = 1;while (SSPCON2bits.PEN);//SSP1IF=0;}void i2c_write(uint8_t i2c_data){i2c_is_idle();SSPBUF = i2c_data;//i2c_is_idle();}uint8_t i2c_read(uint8_t ack){uint8_t recieve =0;i2c_is_idle();SSPCON2bits.RCEN = 1;while(SSPSTATbits.BF != 1);recieve = SSPBUF;SSPCON2bits.ACKEN = ack;return recieve;}void i2c_init(void){TRISCbits.TRISC0 = 1; //I2C pin turn INPUTTRISCbits.TRISC1 = 1; //I2C pin turn INPUTSSP1DATPPS = 0x11; //connecting pins and peripheral explicitlySSP1SSPPS = 0x10;RC0PPS = 0x10; //connecting peripheralRC1PPS = 0x11;SSPSTATbits.SMP = 1; //activating and configuring msspSSPSTATbits.CKE = 0; //disable SMBusSSPCONbits.SSPM = 0x08; //I'm the master hereSSPADD = 79; //32MHz -> 100kHz I2CSSPCONbits.SSPEN = 1;//configures pins as serial input}void main(void) {ANSELCbits.ANSC0 = 0;ANSELCbits.ANSC1 = 0; //Disable analog input I2C pinsTRISCbits.TRISC2=0; //Debugging LED pin (PIN-LED-RES-GND)TRISCbits.TRISC0=0; //set them as output first due to bugTRISCbits.TRISC1=0; //set them as output first due to bug//__delay_ms(5);LATCbits.LATC1=0;//I2C pins output low against bug, turned UNPUT in i2c_init()LATCbits.LATC0=0;//LATCbits.LATC2 = 0; //LED offADCON0bits.ADON=0; //ADC power offi2c_init();i2c_start();i2c_write(0x3c);i2c_stop();while(1){LATCbits.LATC2 = 1; //blink LED__delay_ms(500);LATCbits.LATC2 = 0;__delay_ms(500);}return;}and it's getting stuck here in the loop forever:Code:void i2c_is_idle(void){while(!PIR1bits.SSP1IF){};PIR1bits.SSP1IF = 0; // clear flag}I've been trying to see anything but a flat line on a scope for 2 weeks already. I really want to make friends with PIC, I find a challenge of reading datasheets and understanding how it works interesting, but it's one of the few cases in my life when I googled my fingers to blood and I just can't get it running. If someone with experience goes just give me a helpful kick in the right direction, I would appreciate a lot (if that's going to include interrupts, please, with details if possible).Thank you

author: JackJones
author_rank: Regular Contributor
timestamp: June 10, 2020, 09:19:28 am
content: QuoteIt looks like SSP1IF deals with interrupts, so it makes sense that it would get stuck there if you don't have interrupts enables.You can use the MPLAB Code Configurator to spit out all the required code and config bits btw, I'd suggest you give it a try. The I2C code it gives is pretty convoluted and hard to read (for me anyway), but it is ready to use.

author: ggchab
author_rank: Frequent Contributor
timestamp: June 10, 2020, 09:20:05 am
content: I did not read all your code but the "i2c_idle()" function is a bit strange: if there is no I2C activity, it will never return as SSPIF will never be set to 1.So, the "i2c_start()" function will never return!

author: ggchab
author_rank: Frequent Contributor
timestamp: June 10, 2020, 09:21:59 am
content: SSPIF will be set even if the interrupt flag SSPIE is disabled.

author: ilyus
author_rank: Newbie
timestamp: June 10, 2020, 09:40:00 am
content: I've removed all links to wait via polling SSP1IF, since I can wait like while(start bit set). So now it's getting stuck at:Code:void i2c_start(void){//i2c_is_idle();SSP1CON2bits.SEN = 1; // Initiate START cyclewhile(SSP1CON2bits.SEN);LATCbits.LATC2 = 1; //blink LED__delay_ms(500);LATCbits.LATC2 = 0;__delay_ms(500);}LED blinks if before that while. Of course I tried removing LED lines and delays to make sure I don't disrupt communication with my LED blinking. No change. So I can't generate Start Bit obviously. What's not obvious - why...

author: JPortici
author_rank: Super Contributor
timestamp: June 10, 2020, 10:01:47 am
content: Re check you pin assignment!SSP1CLKPPS is for SCLSSP1DATPPS is for SDARC0PPS and RC1PPS are also wrong, see REGISTER 13-2 in the datasheet you linked

author: ilyus
author_rank: Newbie
timestamp: June 10, 2020, 10:11:19 am
content: Corrected stuff. Wrote full binary straight from the datasheet to be on the safe side. No changes. Idle at 5V.Code:SSP1CLKPPS = 0b00010000;SSP1DATPPS = 0b00010001; //connecting pins and peripheral explicitlyRC0PPS = 0b00011000; //connecting peripheralRC1PPS = 0b00011001;I have to note that multiple youtube examples don't have these lines at all

author: ilyus
author_rank: Newbie
timestamp: June 10, 2020, 10:59:06 am
content: Funny update: I haven't changed a single letter in the code, but it's behaving differently now. Originally, it was pretty expected 5V always. Now when I trigger oscilloscope on MCU reset, turns out SDA/SCL lines were around 0v before MCU reset and sit at 5V dead after MCU reset.The code now GOES through I2C_start but hangs in a similar loop in i2c_write, oscilloscope pattern is weird. I tried to start another project in MPLAB and use MCC to set up I2C, but there is some bug and I can't select I2C in drop-down menu (it's selectable, clickable, but when I click on I2C, dropdown menu closes with SPI selected. Both MSSP1 and MSSP2. App restarted, nothing helped). So I deleted that project and returned to the original program posted here.A picture of my oscilloscope attachedSo I decided to go back to full manual mode, uploaded the code and saw this new behavior.I have a feeling PIC MCUs are doing anything possible to prevent me from programming them, I have to admit, I'm getting desperate.Even when out of desperation I got MCU 100% EXACTLY like in Youtube example, circuit 99% EXACTLY like in example (another I2C device connected, but I just want to see communication first) and code 100% EXACTLY like in example (on PIC16F877A), the thing works in example, but doesn't work for meP.S. apologies for a little rant, I really-really want to get it running