Сделал еще один двухдневный подход к i2c slave на PIC. Сил и нервов уже никаких не осталось. Ладно, к делу. Есть сетап: pic18f25k22 читает байт из i2c, пишет на его место другой байт, читает снова и сверяет записанное и прочитанное.
Функция чтения: старт - байт адреса+бит записи - запись адреса регистра - рестарт - байт адреса+бит чтения - чтение значения регистра - стоп.
Функция записи - старт - байт адреса+бит записи - запись адреса регистра - запись значения в регистр - стоп.
Функции проверены-перепроверены на датчике цвета, предполагается, что этот поллер нормально работает. Когда слейв от него отключен, он спокойно пуляет в пустоту адреса, ничего не получает и т.д. Подключаем слейв - поллер тыркается в него и зависает.
Теперь слейв - pic16f1827. Все на прерываниях, пять условий в соответствии с AN734. В каждом условии сделал выгрузку в УАРТ одного байта. Судя по этой отладочной информации, первое и последнее условие, в которое попадает обработчик прерывания - это условие №3 - STATE 3: MASTER READ, LAST BYTE WAS AN ADDRESS
• S = 1 (Start condition occurred last)
• R/W = 1 (Master reading data from the slave)
• D/A = 0 (Last byte was an address)
А, да, еще важно - включен слейв-режим семибайтный с прерываниями на старте/стопе.
Код сетапа камня слейва:
- Код: Выделить всё
//-----------------------------------------------------------------
//-----------------------------------------------------------------
//i2c setup
//SSP1CON1 = 0b00011110;
//SSP1CON1bits.WCOL
//SSP1CON1bits.SSP1OV
//SSP1CON1bits.SSP1EN
SSP1CON1bits.CKP = 1; //enable clock
SSP1CON1bits.SSPM3 = 1; //i2c
SSP1CON1bits.SSPM2 = 1; //slave
SSP1CON1bits.SSPM1 = 1; //7-bit address
SSP1CON1bits.SSPM0 = 0; // w START-STOP interrupts
SSP1ADD = I2C_ADDR;
//SSP1STAT = 0b10000000;
SSP1STATbits.SMP = 1; //1 = Slew rate control disabled for standard speed mode (100 kHz and 1 MHz)
SSP1STATbits.CKE = 1; //0 = Disable SM bus� specific inputs
//SSP1CON2 = 0x00;
SSP1CON2bits.GCEN = 1; //0 = General call address disabled
SSP1CON2bits.SEN = 1; //1 = Clock stretching enabled
//SSP1CON3 = 0b00011000;
SSP1CON3bits.BOEN = 1; //1 = SSPxBUF is updated and ACK is generated for a received address/data byte, ignoring the
//state of the SSPxOV bit only if the BF bit = 0.
SSP1CON3bits.SDAHT = 1; //1 = Minimum of 300 ns hold time on SDAx after the falling edge of SCLx
SSP1CON3bits.AHEN = 0;
SSP1CON3bits.DHEN = 0;
//SSP1MSK = 0xFF;
SSP1CON1bits.SSPEN = 1;
SSP1STAT = 0x00;
SSP1IF = 0;
SSP1IE = 1;
//-----------------------------------------------------------------
//-----------------------------------------------------------------
PEIE = 1;
GIE = 1;
Код обработчика прерывания:
- Код: Выделить всё
if (SSP1IF && SSP1IE)
{
// unsigned char SSPSTAT_TEMP = SSPSTAT & 0b00101101;
if ((SSP1STATbits.S) && (!SSP1STATbits.R_nW) && (!SSP1STATbits.D_nA) && (SSP1STATbits.BF))
//if (!(0b00001001 ^ SSPSTAT_TEMP))
//STATE 1: MASTER WRITE, LAST BYTE WAS AN ADDRESS
{
while (!TXIF);
TXREG = 'A';
SSP1IF = 0;
unsigned char xxxx = SSPBUF;
if (!SSP1CON1bits.CKP) SSP1CON1bits.CKP = 1;
i2c_set_register = 1;
while (!TXIF);
TXREG = '.';
}
/* else if ((SSP1STATbits.S) && (!SSP1STATbits.R_nW) && (SSP1STATbits.D_nA) && (SSP1STATbits.BF))
//else if (!(0b00101001 ^ SSPSTAT_TEMP))
//STATE 2: MASTER WRITE, LAST BYTE WAS DATA
{
while (!TXIF);
TXREG = 'B';
SSP1IF = 0;
if (i2c_set_register)
{
i2c_register = SSPBUF;
i2c_set_register = 0;
} else
{
if (i2c_register < sizeof(CONTROL_REG))
CONTROL_REG[i2c_register] = SSPBUF;
}
if (!SSP1CON1bits.CKP) SSP1CON1bits.CKP = 1;
while (!TXIF);
TXREG = ',';
}
else if ((SSP1STATbits.S) && (SSP1STATbits.R_nW) && (!SSP1STATbits.D_nA))
//else if (!(0b00001100 ^ (SSPSTAT_TEMP & 00101100)))
//STATE 3: MASTER READ, LAST BYTE WAS AN ADDRESS
{
while (!TXIF);
TXREG = 'C';
SSP1IF = 0;
unsigned char xxxxx = SSP1BUF;
//while (SSP1STATbits.BF) SSPBUF;
while (SSP1CON1bits.WCOL)
{
SSP1CON1bits.WCOL = 0;
SSPBUF = 0x11;//CONTROL_REG[i2c_register];
}
SSP1BUF = 'T';
SSP1CON1bits.CKP = 1;
//if (!SSP1CON1bits.CKP) SSP1CON1bits.CKP = 1;
while (!TXIF);
TXREG = '-';
}
else if ((SSP1STATbits.S) && (SSP1STATbits.R_nW) && (SSP1STATbits.D_nA) && (!SSP1STATbits.BF))
//else if (!(0b00101100 ^ SSPSTAT_TEMP))
//STATE 4: MASTER READ, LAST BYTE WAS DATA
{
while (!TXIF);
TXREG = 'D';
SSP1IF = 0;
//while (SSP1STATbits.BF) SSPBUF;
while (SSP1CON1bits.WCOL)
{
SSP1CON1bits.WCOL = 0;
SSPBUF = 0x11;//CONTROL_REG[i2c_register];
}
if (!SSP1CON1bits.CKP) SSP1CON1bits.CKP = 1;
while (!TXIF);
TXREG = ';';
}
else if ((SSP1STATbits.S) && (SSP1STATbits.D_nA) && (!SSP1STATbits.BF) && (SSP1CON1bits.CKP))
//else if ((!(0b00101000 ^ (SSPSTAT_TEMP & 00101001))) && SSP1CON1bits.CKP)
//STATE 5: MASTER NACK
{
while (!TXIF);
TXREG = 'E';
SSP1IF = 0;
//SSPBUF;
i2c_register = 0x00;
if (!SSP1CON1bits.CKP) SSP1CON1bits.CKP = 1;
while (!TXIF);
TXREG = '#';
}
else if ((SSP1STATbits.P))
//STATE 6: STOP
{
while (!TXIF);
TXREG = 'F';
SSP1IF = 0;
//SSPBUF;
i2c_register = 0x00;
if (!SSP1CON1bits.CKP) SSP1CON1bits.CKP = 1;
while (!TXIF);
TXREG = '/';
}
else
{
while (!TXIF);
TXREG = 'G';
SSP1CON1bits.SSPEN = 0;
SSP1IF = 0;
SSP1CON1bits.SSPEN = 1;
while (!TXIF);
TXREG = '&';
}*/
}
Ребят, помогите, а то уже застрелиться охота. Спасибо заранее.