I am working on a project using the dsPIC33FJ128MC510, and I spent a week trying to solve a problem with the I2C bus.
My problem is that the I2C bus (both SDA and SCL) is high all the time. No clock and no data. EDIT : while doing step by step I can see BCL bit (from I2C1STAT register) going high as soon as I want to emit a START condition.
I checked the hardware configuration and everything is fine. I have an automatic bidirectionnal level shifter compatible with open-drain, external 4k7 pull-up on 3V3 and 5V sides (see schematic below):
The level shifter is working fine as I can see the correct waveforms when generating DIY pulses instead of enabling the I2C module. As soon as I enable the I2C module the problem appears.
Please note that the dsPIC33FJ128MC510 was not supported by MCC so I had to use the I2C MCC file from another dsPIC33F microcontroller but registers seem to be compatible between the two microcontrollers. I just changed the I2C_Initialize function and the clock configuration. See below the code for I2C_Initialization():
void I2C1_Initialize(void)
{
i2c1_object.pTrHead = i2c1_tr_queue;
i2c1_object.pTrTail = i2c1_tr_queue;
i2c1_object.trStatus.s.empty = true;
i2c1_object.trStatus.s.full = false;
i2c1_object.i2cErrors = 0;
// initialize the hardware
// Baud Rate Generator Value: I2CBRG 76;
I2C1BRG = 0x4C; // @TODO : 26 before
// ACKEN disabled; STRICT disabled; STREN disabled; GCEN disabled; SMEN disabled; DISSLW enabled; I2CSIDL disabled; ACKDT Sends ACK; SCLREL Holds; RSEN disabled; A10M 7 Bit; PEN disabled; RCEN disabled; SEN disabled; I2CEN enabled;
I2C1CON = 0x8000;
// BCL disabled; P disabled; S disabled; I2COV disabled; IWCOL disabled;
I2C1STAT = 0x00;
/* I2C1 Master Events */
// clear the master interrupt flag
IFS1bits.MI2C1IF = 0;
// enable the master interrupt
IEC1bits.MI2C1IE = 1;
}
Here is the code for the clock configuration:
void CLOCK_Initialize(void)
{
// FRCDIV FRC/1; PLLPRE 8; DOZE 1:8; PLLPOST 1:8; DOZEN disabled; ROI disabled;
CLKDIV = 0x30C6;
CLKDIVbits.PLLPOST = 1; // TODO : comment if it doesn't solve the CAN problem. UART baudrate is now x2. Need to multiply U1BRG by 2 in UART1.C and adapt TIMERS
// Fosc is now 32MHz. Fp= 16MHz
// CLKDIVbits.DOZE = 1; // TODO : comment if it doesn't solve the CAN problem. Now Fcy = 8MHz (same as before normally ...)
// CLKDIVbits.DOZEN = 0; // TODO : comment if it doesn't solve the CAN problem. Now Fcy = 8MHz (same as before normally ...)
// TUN Center frequency;
OSCTUN = 0x00;
// PLLDIV 137;
PLLFBD = 0x89;
// AD1MD enabled; PWMMD enabled; T3MD enabled; T4MD enabled; T1MD enabled; U2MD enabled; T2MD enabled; U1MD enabled; SPI2MD enabled; SPI1MD enabled; C1MD enabled; T5MD enabled; I2C1MD enabled;
PMD1 = 0x00;
// IC4MD enabled; IC3MD enabled; OC1MD enabled; IC2MD enabled; OC2MD enabled; IC1MD enabled; OC3MD enabled; OC4MD enabled;
PMD2 = 0x00;
// CMPMD enabled;
PMD3 = 0x00;
// CF no clock failure; NOSC FRCPLL; CLKLOCK unlocked; OSWEN Switch is Complete;
__builtin_write_OSCCONH((uint8_t) (0x01));
__builtin_write_OSCCONL((uint8_t) (0x01));
// Wait for Clock switch to occur
while (OSCCONbits.OSWEN != 0);
while (OSCCONbits.LOCK != 1);
}
And here are the two functions thare are called in the main(). These two functions worked with another microcontroller dsPIC33EV128GM106 so the problem is probably not here.
void setup_SHT31(void) {
SHT31.SHT31_ID = 0x44;
pfSHT31_main.tempsEnMs = &tempsEnMsDspic;
pfSHT31_main.I2C1_MasterReadTRBBuild = &I2C1_MasterReadTRBBuild;
pfSHT31_main.I2C1_MasterTRBInsert = &I2C1_MasterTRBInsert;
pfSHT31_main.I2C1_MasterWriteTRBBuild = &I2C1_MasterWriteTRBBuild;
SHT31_initialize(&SHT31, &pfSHT31_main);
}
void SHT31_initialize(TypeSHT31 *ID, Type_pfSHT31 *pfSHT31 )
{
pfSHT31_lib = (*pfSHT31); //recopie des pointeurs de fonctions
}
void SHT31_readData(TypeSHT31 *ID)
{
(*ID).temps_init = pfSHT31_lib.tempsEnMs();
SHT31_I2C1_MESSAGE_STATUS status = SHT31_I2C1_MESSAGE_PENDING;
static SHT31_I2C1_TRANSACTION_REQUEST_BLOCK trb[2];
(*ID).tampon_ecriture[0] = 0x2C; //clock streching
(*ID).tampon_ecriture[1] = 0x0D; //med repetability
status = SHT31_I2C1_MESSAGE_PENDING;
pfSHT31_lib.I2C1_MasterWriteTRBBuild(&trb[0], &(*ID).tampon_ecriture, 2, (*ID).SHT31_ID);
pfSHT31_lib.I2C1_MasterTRBInsert(1, &trb[0], &status);
while(status == SHT31_I2C1_MESSAGE_PENDING && (pfSHT31_lib.tempsEnMs() - (*ID).temps_init) < SHT31_TIMOUT_in_ms)
{
Nop(); //stay here
}
//attente 5ms // temps de conversion moyen
while ((pfSHT31_lib.tempsEnMs() - (*ID).temps_init) < SHT31_CONV_TIME_in_ms)
{
Nop();
}
status = SHT31_I2C1_MESSAGE_PENDING;
pfSHT31_lib.I2C1_MasterReadTRBBuild(&trb[0], (*ID).tampon_lecture, 6, (*ID).SHT31_ID);
pfSHT31_lib.I2C1_MasterTRBInsert(1, &trb[0], &status);
while(status == SHT31_I2C1_MESSAGE_PENDING && (pfSHT31_lib.tempsEnMs() - (*ID).temps_init) < SHT31_TIMOUT_in_ms)
{
Nop(); //stay here
}
if ((pfSHT31_lib.tempsEnMs() - (*ID).temps_init) < SHT31_TIMOUT_in_ms)
{
(*ID).readTemperature.Bits.MSB = (*ID).tampon_lecture[0];
(*ID).readTemperature.Bits.LSB = (*ID).tampon_lecture[1];
(*ID).readHumidity.Bits.MSB = (*ID).tampon_lecture[3];
(*ID).readHumidity.Bits.LSB = (*ID).tampon_lecture[4];
///conversion
(*ID).Temperature_in_degres = -45.0 + 175.0 * (*ID).readTemperature.Word / 65535.0;
(*ID).Humidity_in_pc = 100.0 * (*ID).readHumidity.Word / 65535.0;
(*ID).status = 1;
}
else
{
(*ID).status = 2;
}
}
Any help would be greatly appreciated!