No hay señal de reloj en el pin SCL de PIC16F1618

0

He estado intentando configurar I2C en el microcontrolador PIC16F1618. Estoy usando MPLAB X IDE, junto con el compilador xc8. El código MSSP se está generando a través del configurador de códigos MPLAB. He configurado la configuración para que sea la interrupción maestra I2C, la frecuencia de reloj sea 62.5KHz. La velocidad de giro es la velocidad estándar, el tiempo de retención SDA es de 300 ns. La dirección del esclavo será de 7 bits. He configurado RC0 para que sea SDA y RC1 para que sea SCL. Así que mi inicialización I2C generada se ve así,

void I2C_Initialize(void) {
    i2c_object.pTrHead = i2c_tr_queue;
    i2c_object.pTrTail = i2c_tr_queue;
    i2c_object.trStatus.s.empty = true;
    i2c_object.trStatus.s.full = false;

    i2c_object.i2cErrors = 0;

    // R_nW write_noTX; P stopbit_notdetected; S startbit_notdetected; BF RCinprocess_TXcomplete; SMP Standard Speed; UA dontupdate; CKE Idle to Active; D_nA lastbyte_address; 
    SSP1STAT = 0x80;
    // SSPEN enabled; WCOL no_collision; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD; SSPOV no_overflow; 
    SSP1CON1 = 0x28;
    // ACKTIM ackseq; SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 300ns; AHEN disabled; 
    SSP1CON3 = 0x08;
    // Baud Rate Generator Value: SSP1ADD 3;   
    SSP1ADD = 0x03;

    /* Byte sent or received */
    // clear the master interrupt flag
    PIR1bits.SSP1IF = 0;
    // enable the master interrupt
    PIE1bits.SSP1IE = 1;

}

Soy muy nuevo en los microcontroladores PIC, ¿podría ayudarme donde está el problema? Estoy usando PIC16F1618. No puedo ver ninguna forma de onda cuando conecto mi osciloscopio al pin SCL. La salida es siempre BAJA. Si conecto una resistencia de pull up, el pin siempre estará en HIGH lógico. También he intentado enviar algunos comandos de lectura / escritura para comprobar si el reloj se inicia, pero lamentablemente no lo hace. He trabajado con controladores ARM y en eso, después de la inicialización, podré observar las señales del reloj.

en main.c

I2C_Initialize();
bmp280.dev_addr = 0x77;
init_check = bmp280_init(&bmp280);

while (1) {        
        bmp280_read_uncomp_pressure(&tempVar);
}

bmp280.c

BMP280_RETURN_FUNCTION_TYPE bmp280_init(bmp280_t *temp_bmp280)
{
    /* variable used to return communication result*/
    BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
    uint8_t v_data_u8 = BMP280_INIT_VALUE;

    p_bmp280 = temp_bmp280;/* assign BMP280 ptr */
    /* read chip id */
    com_rslt = i2cbus_read(p_bmp280->dev_addr,
    BMP280_CHIP_ID_REG, &v_data_u8,
    BMP280_GEN_READ_WRITE_DATA_LENGTH);
    //com_rslt = p_bmp280->BMP280_BUS_READ_FUNC(p_bmp280->dev_addr,
    //BMP280_CHIP_ID_REG, &v_data_u8,
    //BMP280_GEN_READ_WRITE_DATA_LENGTH);/* read Chip Id */
    p_bmp280->chip_id = v_data_u8;
    /* readout bmp280 calibparam structure */
    com_rslt += bmp280_get_calib_param();
    return com_rslt;
}

BMP280_RETURN_FUNCTION_TYPE bmp280_read_uncomp_pressure(int32_t *v_uncomp_pressure_s32)
{
    /* variable used to return communication result*/
    BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
    /* Array holding the MSB and LSb value
    a_data_u8[0] - Pressure MSB
    a_data_u8[1] - Pressure LSB
    a_data_u8[2] - Pressure LSB
    */
    uint8_t a_data_u8[BMP280_PRESSURE_DATA_SIZE] = {BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE};
    /* check the p_bmp280 struct pointer as NULL*/
    if (p_bmp280 == BMP280_NULL) {
        return  E_BMP280_NULL_PTR;
        } else {
            com_rslt = i2cbus_read(p_bmp280->dev_addr,
                       BMP280_PRESSURE_MSB_REG,
                       a_data_u8, BMP280_PRESSURE_DATA_LENGTH);
            *v_uncomp_pressure_s32 = (int32_t)(
                   (((uint32_t)(a_data_u8[BMP280_PRESSURE_MSB_DATA]))
                   << BMP280_SHIFT_BIT_POSITION_BY_12_BITS) |
                   (((uint32_t)(a_data_u8[BMP280_PRESSURE_LSB_DATA]))
                   << BMP280_SHIFT_BIT_POSITION_BY_04_BITS) |
                   ((uint32_t)a_data_u8[BMP280_PRESSURE_XLSB_DATA] >>
                   BMP280_SHIFT_BIT_POSITION_BY_04_BITS));
        }
    return com_rslt;
}

estructura bmp280_t utilizada

typedef struct {
    struct bmp280_calib_param_t calib_param;/**<calibration data*/

    uint8_t chip_id;/**< chip id of the sensor*/
    uint8_t dev_addr;/**< device address of the sensor*/

    uint8_t oversamp_temperature;/**< temperature over sampling*/
    uint8_t oversamp_pressure;/**< pressure over sampling*/

}bmp280_t;

en i2c_wrapper.c

int8_t i2cbus_read(uint8_t device_addr, uint8_t register_addr, uint8_t* register_data, uint8_t rd_len)
{
    I2C_MESSAGE_STATUS status;
    uint16_t    timeOut;
    uint16_t    counter;
    uint8_t     *pD; 
    int8_t      ret = 0;

    pD = register_data;

    for (counter = 0; counter < rd_len; counter++)
    {

        // Now it is possible that the slave device will be slow.
        // As a work around on these slaves, the application can
        // retry sending the transaction
        timeOut = 0;
        while(status != I2C_MESSAGE_FAIL)
        {
            // write one byte to slave i2c device, which is the register address
            I2C_MasterWrite(&register_addr, 1, device_addr, &status);

            // wait for the message to be sent or status has changed.
            while(status == I2C_MESSAGE_PENDING);

            if (status == I2C_MESSAGE_COMPLETE)
                break;

            // if status is  I2C_MESSAGE_ADDRESS_NO_ACK,
            //               or I2C_DATA_NO_ACK,
            // The device may be busy and needs more time for the last
            // write so we can retry writing the data, this is why we
            // use a while loop here

            // check for max retry and skip this byte
            if (timeOut == MAX_RETRY)
                break;
            else
                timeOut++;
        }

        if (status == I2C_MESSAGE_COMPLETE)
        {

            // this portion will read the byte from the memory location.
            timeOut = 0;
            while(status != I2C_MESSAGE_FAIL)
            {
                // read from the slave device
                I2C_MasterRead(pD, 1, device_addr, &status);

                // wait for the message to be sent or status has changed.
                while(status == I2C_MESSAGE_PENDING);

                if (status == I2C_MESSAGE_COMPLETE)
                    break;

                // if status is  I2C_MESSAGE_ADDRESS_NO_ACK,
                //               or I2C_DATA_NO_ACK,
                // The device may be busy and needs more time for the last
                // write so we can retry writing the data, this is why we
                // use a while loop here

                // check for max retry and skip this byte
                if (timeOut == MAX_RETRY)
                    break;
                else
                    timeOut++;
            }
        }

        // exit if the last transaction failed
        if (status == I2C_MESSAGE_FAIL)
        {
            ret = -1;
            break;
        }

        pD++;
        register_addr++;

    }
    return (ret);
}

I2C_MasterWrite y I2C_MasterRead es generado por el configurador de códigos que está presente en i2c.c

    
pregunta Abhishek G

2 respuestas

0

Es probable que necesites resistencias pull-up en las líneas I2C. Estoy usando ~ 5k resistencias para jalar las líneas I2C hasta Vdd. Las flexiones internas son demasiado débiles para usarlas con I2C. No tengo nada conectado al bus I2C, por lo que la comunicación termina en un NAK:

Este es mi principal:

void main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    while (1)
    {
        I2C_MESSAGE_STATUS status = I2C_MESSAGE_PENDING;
        uint8_t buffer[20];
        I2C_MasterRead(buffer, 5, 42, &status);
        while(I2C_MESSAGE_PENDING == status);
        __delay_ms(10);
        status = I2C_MESSAGE_PENDING;
        I2C_MasterWrite(buffer, 5, 42, &status);
        __delay_ms(250);
    }
}

Todo lo demás es generado por MCC para un PIC16F1619 en un tablero de curiosidad. Utilicé C0 y C1 para mis líneas I2C, como en tu caso.

Estoy usando MPLABX 3.30, con MCC 3.15 y XC8 1.37.

    
respondido por el Ryan B
0
  

... pin de SCL. La salida es siempre BAJA. Si conecto un pull up   resistencia, entonces el pin siempre estará en el nivel lógico ALTO.

Parece que no tienes un pullup en la línea DAT. Necesitas pullups de resistencia separados en ambas líneas SCL y DAT. Puedes comenzar con 4.7k.

Sin la extracción de la línea DAT, estará en la lógica 0, que le indica al controlador I2C que el bus está ocupado. Su depurador mostrará que su código está atascado en la línea de abajo esperando que el autobús se libere:

  

while (estado == I2C_MESSAGE_PENDING);

Incluso si no hay dispositivos I2C en el bus, solo agregar esos controles debe darte un cambio de SCL y el depurador debería superar esa línea de espera.

Por supuesto, recibirá un error NAK ya que no hay un dispositivo I2C para responder, pero al menos eso lo hará superar su primer obstáculo. (Al ser nuevo en I2C, tendrás más obstáculos divertidos para saltar :)

    
respondido por el Vince Patron

Lea otras preguntas en las etiquetas