Доброго времени суток, друзья. Столкнулся с ужасной проблемой, уже две недели сижу на PICах точёных, не могу запустить I2C. Две недели почти ежедневного многочасового гуглинга (мне на работе можно иногда уйти в research). Перегуглил всё на свете, на крупных иностранных форумах спрашивал (Electrical Engineering Stack Exchange, EEVBlog Forum, даже купил по мегаскидке курс на Udemy, где делалось прямо то, что мне надо, и нифига), никто не может помочь. И непонятно, что я делаю не так.
Я даже нашёл на ютубе пример с другим микроконтроллером, купил его специально, чтобы просто скопипастить пример. То есть тот же MCU, та же цепь, тот же код. И нифига. Но сейчас не об этом. В принципе, не особо важно, какой микро, у них там регистры одинаковые, просто пины другие. Да и всё равно всё одинаково не работает. (это был PIC16F877A)
А теперь по сути:
PIC16F18326 DIP на бредборде. Внутренний кристалл 32МГц, моргаю ЛЕДками, как боженька, паузы правильные. MPLAB X 5.40, XC8 2.20. MCC глючит и не даёт выбрать I2C при конфигурации MSSP порта, да и ручками всё делать интереснее, не то что бы это сильно сложно по идее.
Протокол I2C изучил, примеры в интернете разобрал, в даташите уже 2 недели сижу, всё понимаю, знаю, что делаю, но ничего не работает. Уже начинаю думать, что бракованные чипы, но не может быть 2 разных бракованных микроконтроллера, купленных в разные дни и в разных местах. Дело явно в другом. С другой стороны, копипаста работающей на видео схемы вплоть до последней буквы кода и точно такой же модели мокроконтроллера тоже не работает. Странно.
Юзаю MSSP1, по дефолту он на пинах RC0, RC1, подтяжки по 4.7к (пробовал другие).
Задача: просто увидеть коммуникацию на осциллографе. Я уже потом напишу без проблем драйвера подо что угодно, даташитов не боюсь.
Использую LED для отладки - включаю после одной команды, после следующей, смотрю, что будет. Сейчас я заloopлен в моменте отправки байта. Пик вечно ждёт отправки, на осциллографе её нет, и вообще, там всё странно.
Пробовал разные варианты кода. Последний вот (там есть функции с чтением, но я просто хочу пока что отправить байт и видеть на SCL хоть что-то кроме гладкой линии).
На изображении осциллограмма. Неважно, что я делаю, оно всегда выглядит так и никак иначе. Я уже почти в отчаянии, никто помочь не может. Пробовал вручную и компараторы, и ADC отключать, уже чего только ни пробовал. Никакой реакции вообще.
P.S. осциллограмма начинается с 0в, потому что обе линии притянуты вниз по итогам предыдущего выполнения программы. Спустя секунду после запуска MCU линия SDA падает в ноль, SCL где-то около 1в. И так остаются навсегда. Программа в loop'e. В остальном ведут себя абсолютно синхронно.
P.P.S. пробовал использовать SSP1IF, если есть while SSP1IF, то виснет в этом его лупе и обе линии сидят на 5В пожизненно.
P.P.P.S. пока без interrupt'ов, пожалуйста, либо распишите их детальнее. Что-то в них понимаю, но особо не пользовался пока что на пиках
Код: Выделить всё
// 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>
#define _XTAL_FREQ 32000000
#define STOP_BIT (SSP1STATbits.P)
#define START_BIT (SSP1STATbits.S)
#define I2C_TX_ST (SSP1STATbits.R_nW) //1 = Transmit is in progress
#define I2C_RX_ST (SSP1STATbits.BF) // Receive complete, SSPxBUF is full
#define WR_COL_BIT (SSP1CON1bits.WCOL) //Write Collision Detect bit- must be Cleared in software
#define RX_OV_BIT (SSP1CON1bits.SSPOV) // Receive Overflow Indicator bit- must be Cleared in software
#define ACK_ST (!SSP1CON2bits.ACKSTAT) //Acknowledge Status bit
#define ACK (SSP1CON2bits.ACKDT=0) //Acknowledge DATA bit, 0 = Acknowledge
#define NACK (SSP1CON2bits.ACKDT=1)
#define ACK_EN_BIT (SSP1CON2bits.ACKEN) //Acknowledge Sequence Enable bit
#define RC_EN_BIT (SSP1CON2bits.RCEN) //Receive Enable bit
#define STOP_EN_BIT (SSP1CON2bits.PEN) //Stop Condition Enable bit
#define RS_EN_BIT (SSP1CON2bits.RSEN) //Repeated Start Condition Enable bit
#define START_EN_BIT (SSP1CON2bits.SEN)//Start Condition Enable/
#define FOSC (32000000)
#define I2C_CLK (100000)
#define SSP_ADD ((int)((FOSC/4.0/I2C_CLK)-1))
#define SSP_EN (SSP1CON1bits.SSPEN)
#define DEV_ADD (0x3C)
#define DEV_ADDWR (DEV_ADD &(0xFE))
#define DEV_ADDRD (DEV_ADD |(0x01))
void I2C_Init(void)
{
SSP_EN=0;
INTCONbits.GIE=0;
PPSLOCK = 0x55;
PPSLOCK = 0xAA;
PPSLOCKbits.PPSLOCKED = 0x00; // unlock PPS
SSP1CLKPPS = 0x10; //SSP1 CLK -> RC0;
RC0PPS = 0x18; //RC0->SCL1;
SSP1DATPPS = 0x11; //SSP1 DAT -> RC1;
RC1PPS=0x19 ;//RC1->SDA1
PPSLOCK = 0x55;
PPSLOCK = 0xAA;
PPSLOCKbits.PPSLOCKED = 0x01; // lock PPS
SSP1STATbits.SMP=1;//Slew rate control disabled for Standard Speed mode
SSP1STATbits.CKE=0; //Disable SMBus specific inputs
SSP1CON1bits.SSPM=8; // I2C Master mode, clock = FOSC / (4 * (SSPxADD+1))
SSP1CON2bits.GCEN=0;// General call address disabled
SSP1CON3bits.PCIE=0;// NO INTERRUPT FOR STOP
SSP1CON3bits.SCIE=0; // NO INTERRUPT ON START BIT
SSP1CON3bits.SDAHT=1; //Minimum of 300 ns hold time on SDA after the falling edge of SCL
// SSP1MSKbits.SSPMSK=0;//The received address bit n is not used to detect I2C address match
SSP1ADD=SSP_ADD;
SSP_EN=1;
TRISCbits.TRISC0=1;// RC0- SCL
TRISCbits.TRISC1=1;// RC1- SDA
ANSELCbits.ANSC0=0;
ANSELCbits.ANSC1=0;
ADCON0bits.ADON=0;
}
void I2C_TX(unsigned char txdata)
{
//while(I2C_RX_ST);
WR_COL_BIT=0;
RX_OV_BIT=0;
SSP1BUF=txdata;
while(I2C_TX_ST);
// PIR3bits.SSP1IF=0;
}
void main(void) {
TRISCbits.TRISC0 = 0; //сначала делаю аутпут лоу из-за бага, в функции INIT делаю инпутом. нихрена не меняет на самом деле.
TRISCbits.TRISC1 = 0;
LATCbits.LATC0 = 0;
LATCbits.LATC1 = 0;
TRISCbits.TRISC2 = 0; //DEBUGGING LED PIN OUTPUT
LATCbits.LATC2 = 0; //DEBUGGING LED OFF
I2C_Init();
//__delay_ms(10);
//PIR3bits.SSP1IF=0;
START_EN_BIT=1;
while(START_EN_BIT);
//PIR3bits.SSP1IF=0;
//LATCbits.LATC2 = 1; //DEBUGGING LED ON ЭТО РАБОТАЕТ
I2C_TX(0x3C);
LATCbits.LATC2 = 1; //DEBUGGING LED ON А ЭТО УЖЕ НЕТ
if(ACK_ST)
{
I2C_TX(0xAA);
// send data to be written
if(ACK_ST)
{
I2C_TX(0x22);
if(ACK_ST)
{
STOP_EN_BIT=1;
while(STOP_EN_BIT);
//PIR3bits.SSP1IF=0;
}
else
{
//return;// No acknowledge
}
}
else
{
//return;// No acknowledge
}
}
else
{
//return 0;// No acknowledge
}
//return 1;
STOP_EN_BIT=1;
while(STOP_EN_BIT);
while(1);
return;
}
Очень прошу подсказать, уже реально нет сил, не знаю, куда податься, не понимаю, как люди делают I2C на них и почему моё побуквенное воспроизведение рабочих примеров не работает.
ПОПРАВКА: перенёс проц на другой бредборд. Теперь SCL/SDA оба мертвецки залочились на 5В, но при этом код не лочится на на одном лупе. Просто 5В, но все while проходят. Короче, муть какая-то




