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!
