Nun, aus der von MCC generierten I2C-Schnittstellen-Header-Datei sehe ich keine Möglichkeit, dem Code mitzuteilen, dass er die Methode des wiederholten Starts anstelle von Stopp-Start verwenden soll. Habe auch nichts Konfigurierbares auf der spärlich gefüllten I2C-Seite in MCC gesehen. Also, bevor ich in autp-generiertem Code rumfummele ...
Gibt es eine Möglichkeit, das "richtig" zu machen? Andernfalls muss ich wohl ihren Bibliothekscode durchsuchen und herausfinden, wie ich ihn ändern kann, um das Notwendige zu tun.
Update : Was ich versucht habe, nachdem ich von brhans auf die Statusmaschine aufmerksam gemacht wurde, die die Art der setCallbackX-Funktionen ändert, ist Folgendes:
i2c_error_t i2c_readRegRepeatStart(uint8_t reg, void* data, uint8_t size)
{
i2c_error_t ret;
__i2c_buf.reg = reg;
i2c_setBuffer(&__i2c_buf.reg, 1);
i2c_setDataCompleteCallback( i2c_restartRead, 0 );
ret = i2c_masterOperation(false); // writing the start,addr,reg,restart part
i2c_setDataCompleteCallback( i2c_returnStop, 0 );
if (ret == I2C_NOERR)
{
i2c_setBuffer(data, size);
ret = i2c_masterOperation(true); // reading the data bytes
}
return (ret);
}
Ich nenne das so: i2c_readRegRepeatStart( registerNum, &someUshortVar, 2 ). Dieser Code erzeugt eine Sequenz auf dem Bildschirm des Logikanalysators, die gut beginnt:
So weit, so gut, oder? Naja fast. Anstatt jetzt ein STOP, folgt hier:
Ich habe noch nicht herausgefunden, was los ist. Es scheint im Prinzip, was getan werden soll, und ich habe zurückverfolgt, wo der Pufferzeiger und die Größe in der MCC-Bibliothek festgelegt sind, und es hat eindeutig den Wert 2 (Größe), dann wird der Treiber mit der Durchführung der I2C-Operation beauftragt , und es macht diese seltsamen Sachen.
Das hat geholfen. Habe es aufgegeben, dafür das MCC-Zeug zu verwenden, außer dem zusammengeklickten grundlegenden Peripherie-Init-Zeug. ( Beachten Sie, dass im offiziellen Microchip-Forum gesagt wurde, dass sich die MCC-I2C-Bibliothek derzeit ändert und nicht viel getestet wird. ) Ich habe im Grunde nur einen weiteren Parameter hinzugefügt, um anzugeben, ob ich stop,start verwenden möchte; oder Neustart (auch bekannt als wiederholte Startbedingung), wodurch es so gemacht wird, dass für "Neustart" die Schreibblockroutine das STOP am Ende weglässt und die Leseblockroutine restart() anstelle von start() aufruft. Beachten Sie auch, dass dieser Code linksbündige Slave-Adressen erwartet (Lshift 1).
http://picforum.ric323.com/viewtopic.php?f=76&t=755#
Hier ein Auszug der relevantesten Sachen, inkl. diejenigen meiner Änderungen, die ich erwähnt habe - Sie müssen möglicherweise Dinge ändern, um die richtigen Registerstrukturen vor den Registernamen in diesem Code zu qualifizieren, wenn Sie auch den von MCC generierten Init-Code verwenden, obwohl Sie MCC dann nicht für das eigentliche Geschäft verwenden. Wenn Sie die read-block-Routine verwenden und repeatStart=true übergeben, wird anstelle von stop,start eine wiederholte Startbedingung ausgeführt. Andernfalls wird es stoppen, starten. Damit konnte ich das Gerät lesen, das zuvor das Lesen verweigern würde, sodass die Frage beantwortet ist - nur ohne die MCC-I2C-Zustandsmaschine zu verwenden, sondern sie mit direktem Registerzugriff zu umgehen.
// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit i2c_start(void)
{
BCLIF = 0; //Clear 'Bus collision" flag
SEN = 1; //initiate a START cycle
while (SEN); //wait until it has been sent
return BCLIF; //return value of BCLIF flag
}
// Send an I2C STOP
void i2c_stop(void)
{
PEN = 1; //initiate a STOP cycle
while (PEN); //wait until it has been sent
}
// Send an I2C REPEATED START
void i2c_restart(void)
{
RSEN = 1; //initiate a REPEATED START cycle
while (RSEN); //wait until it has been sent
}
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit i2c_sendbyte(unsigned char dat)
{
SSPBUF = dat;
while (R_W); //wait until byte sent and ACK/NAK received
return ACKSTAT;
}
//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
unsigned char i2c_recvbyte(unsigned char ackflag)
{
RCEN = 1; // initiate a RECEIVE cycle
ACKDT = ackflag; //specify if we should send ACK or NAK after receiving
while (RCEN); //wait until RECEIVE has completed
ACKEN = 1; //initiate an ACK cycle
while (ACKEN); //wait until it has completed
return SSPBUF;
}
//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char i2c_writeblock(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr, bool stop)
{
if (i2c_start() ) //send a start, and check if it succeeded
return 1; //abort if bus collision
//send the I2C slave address (force R/W bit low)
if (i2c_sendbyte(slave_address & 0xFE))
{
i2c_stop(); //if address was NAKed, terminate the cycle
return 2; //and return error code
}
//send the device register index
if (i2c_sendbyte(start_reg))
{
i2c_stop(); //if register was NAKed, terminate the cycle
return 3; //and return error code
}
//send the data. buflen might be zero!
for (; buflen>0; --buflen)
{
if (i2c_sendbyte(*bufptr++))
{
i2c_stop(); //if register was NAKed, terminate the cycle
return 4; //and return error code
}
}
if (stop)
i2c_stop();
return 0; //no error
}
//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char i2c_readblock(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr, bool repeatStart)
{
//do a dummy zero length write cycle to set the register address
unsigned char retval = i2c_writeblock(slave_address, start_reg,0,0, !repeatStart);
if (retval)
{
return retval; //abort if there was an error
}
if (repeatStart)
i2c_restart(); // restart can't fail - if bus remains asserted, there can be no collision
else
//now start the READ cycle
if (i2c_start() ) //send a start, and check if it succeeded
return 1; //abort if bus collision
//send the I2C slave address (force the R/W bit high)
if (i2c_sendbyte(slave_address | 0x01))
{
i2c_stop(); //if address was NAKed, terminate the cycle
return 2; //and return error code
}
//receive the data.
for (; buflen>0; --buflen)
{
unsigned char ackflag = (buflen == 1); //1 if this is the last byte to receive => send NAK
*bufptr++ = i2c_recvbyte(ackflag);
}
i2c_stop();
return 0; //no error
}
brhans
I2C_SetDataCompleteCallback
die FSM-Sequenz von der Standardeinstellung auf ändern,I2C_CallbackReturnStop
bevorI2C_CallbackRestartRead
Sie den I2C-Betrieb starten.Scott Seidmann
sktpin
sktpin
sktpin