Exemplo n.º 1
0
/**
 ****************************************************************************************
 * @brief Initializes the I2C controller
 * @param[in]    buffer     i2c buffer (point to a gobal memory)
 * @param[in]    size       i2c buffer len, = address size + data size
 * @description
 *  The function is used to initialize I2C in slave mode, this function is also
 *  used to enable I2c interrupt, and enable NVIC I2C IRQ.
 *****************************************************************************************
 */
void i2c_init(uint8_t *buffer, uint16_t size)
{
    uint32_t reg;

    i2c_env.i2cOpFsm = I2C_OP_IDLE;
    i2c_env.i2cBufferSize = size;
    i2c_env.i2cBuffer = buffer;

    i2c_reset();

#if CONFIG_I2C_ENABLE_INTERRUPT==TRUE
    /* Enable the I2C Interrupt */
    NVIC_EnableIRQ(I2C_IRQn);
#endif

    /*
        * Mask all slave interrupt in I2C component
        */
    reg = I2C_SLAVE_ADDR(QN9020_I2C_ADDR)   // slave address, slave mode active
        | I2C_MASK_SLAVE_EN                 // slave
        | I2C_MASK_STP_INT_EN               // Enable abnormal stop interrupt
        | I2C_MASK_SAM_INT_EN               // Enable slave address match interrupt, slave mode active
        | I2C_MASK_GC_INT_EN                // Enable general call interrupt, slave mode active
        | I2C_MASK_RX_INT_EN                // Enable RX interrupt
        | I2C_MASK_TX_INT_EN;               // Enable TX interrupt
    i2c_i2c_SetCR(QN_I2C, reg);

    reg = I2C_MASK_RD_EN
        | I2C_MASK_SLV_ACK_SEND;            //ACK
    i2c_i2c_SetTXD(QN_I2C, reg);

}
Exemplo n.º 2
0
/**
 ****************************************************************************************
 * @brief Start a data transmission.
 * @param[in]  saddr         slave device address(7bits, without R/W bit)
 * @return Error code
 * @description
 * This function is used to complete an I2C write transaction from start to stop. All the intermittent steps
 * are handled in the interrupt handler while the interrupt is enabled.
 * Before this function is called, the read length, write length, I2C master buffer,
 * and I2C state need to be filled. Please refer to I2C_BYTE_WRITE().
 * As soon as the end of the data transfer is detected, the callback function is called.
 *****************************************************************************************
 */
static enum I2C_ERR_CODE i2c_write(uint8_t saddr)
{
    uint32_t reg;
    uint32_t timeout = 0;

    if (i2c_bus_check() == I2C_BUS_BUSY) {
        return I2C_CONFLICT;
    }
    else {
        i2c_env.i2cOpFsm = I2C_OP_WRDATA;
    }

    // start write slave address with write bit
    reg = I2C_MASK_WR_EN
        | I2C_MASK_START
        | ((saddr << 1) & 0xFE);
    i2c_i2c_SetTXD(QN_I2C, reg);

    do {
        timeout++;
        if (timeout > I2C_MAX_TIMEOUT) {
            return I2C_TIMEOUT;
        }
#if CONFIG_I2C_ENABLE_INTERRUPT==FALSE
        i2c_polling();
#endif

        if (i2c_env.i2cOpFsm == I2C_OP_ABORT) {
            return I2C_NO_ACK;
        }

    } while (i2c_env.i2cOpFsm != I2C_OP_FINISH);

#if I2C_CALLBACK_EN==TRUE
    // Call end of transmission callback
    if (i2c_env.callback != NULL)
    {
        i2c_env.callback();
    }
#endif

    return I2C_NO_ERROR;
}
Exemplo n.º 3
0
/**
 ****************************************************************************************
 * @brief I2C interrupt handler, deal with slave mode only.
 ****************************************************************************************
 */
void I2C_IRQHandler(void)
{
    uint32_t status;
    uint32_t reg;

    status = i2c_i2c_GetIntStatus(QN_I2C);
    if (status & I2C_MASK_STP_INT) {

        reg = I2C_MASK_RD_EN
            | I2C_MASK_SLV_ACK_SEND;     // ACK
        i2c_i2c_SetTXD(QN_I2C, reg);
        i2c_env.i2cOpFsm = I2C_OP_IDLE;

        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_STP_INT);
    }

    if (status & I2C_MASK_GC_INT) {

        reg = I2C_MASK_RD_EN
            | I2C_MASK_SLV_ACK_SEND;     // ACK
        i2c_i2c_SetTXD(QN_I2C, reg);
        i2c_env.i2cOpFsm = I2C_OP_IDLE;

        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_GC_INT);
    }

    if (status & I2C_MASK_SAM_INT) { // slave adress is match

        reg = i2c_i2c_GetRXD(QN_I2C);
        if (reg & 0x01) { // master read, slave write

            reg = I2C_MASK_WR_EN
                | I2C_MASK_SLV_ACK_SEND     // ACK
                | i2c_env.i2cBuffer[i2c_env.i2cIndex++];
            i2c_env.i2cOpFsm = I2C_OP_WRDATA;
        }
        else { // mast write, slave read

            reg = I2C_MASK_RD_EN
                | I2C_MASK_SLV_ACK_SEND;     // ACK
            i2c_env.i2cOpFsm = I2C_OP_SETADDR;
        }
        i2c_i2c_SetTXD(QN_I2C, reg);
        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_SAM_INT|I2C_MASK_RX_INT);
        status = 0;
    }

    if (status & I2C_MASK_RX_INT) {
        if (i2c_env.i2cOpFsm == I2C_OP_SETADDR) {
            i2c_env.i2cIndex = i2c_i2c_GetRXD(QN_I2C);  // The 1st byte is the index.
            i2c_env.i2cOpFsm = I2C_OP_RDDATA;
        }
        else if (i2c_env.i2cOpFsm == I2C_OP_RDDATA) {
            i2c_env.i2cBuffer[i2c_env.i2cIndex++] = i2c_i2c_GetRXD(QN_I2C);
        }

        if (i2c_env.i2cIndex >= i2c_env.i2cBufferSize) {
            reg = I2C_MASK_RD_EN
                | I2C_MASK_SLV_NACK_SEND;     // NACK
        }
        else {
            reg = I2C_MASK_RD_EN
                | I2C_MASK_SLV_ACK_SEND;     // ACK
        }
        i2c_i2c_SetTXD(QN_I2C, reg);
        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_RX_INT);
    }

    if (status & I2C_MASK_TX_INT) {
        if (!(i2c_i2c_GetSR(QN_I2C) & I2C_MASK_ACK_RECEIVED)) { // ACK == 0,  go on

            if (i2c_env.i2cIndex >= i2c_env.i2cBufferSize) {  // user can modify here
                i2c_env.i2cIndex = 0;
            }

            reg = I2C_MASK_WR_EN
                | I2C_MASK_SLV_ACK_SEND     // ACK
                | i2c_env.i2cBuffer[i2c_env.i2cIndex++];
        }
        else { // NO ACK, SLAVE back to RD
            reg = I2C_MASK_RD_EN
                | I2C_MASK_SLV_ACK_SEND;     // ACK
        }

        i2c_i2c_SetTXD(QN_I2C, reg);
        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_TX_INT);
    }
}
Exemplo n.º 4
0
/**
 ****************************************************************************************
 * @brief I2C interrupt handler, deal with master mode only.
 ****************************************************************************************
 */
void I2C_IRQHandler(void)
{
    uint32_t status;
    uint32_t reg = 0;

    status = i2c_i2c_GetIntStatus(QN_I2C);
    if (status & I2C_MASK_AL_INT) {
        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_AL_INT);
    }

    if (status & I2C_MASK_RX_INT) {
        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_RX_INT);

        // store read result
        i2c_env.i2cBuffer[i2c_env.i2cIndex++] = i2c_i2c_GetRXD(QN_I2C);
        i2c_env.i2cRxCount--;
        if (i2c_env.i2cRxCount > 1) {
            reg = I2C_MASK_RD_EN
                | I2C_MASK_ACK_SEND;         // ACK
        }
        else if (i2c_env.i2cRxCount == 1) {
            reg = I2C_MASK_RD_EN
                | I2C_MASK_NACK_SEND;        // NACK
        }
        else if (i2c_env.i2cRxCount == 0) {  // data rx finish
            reg = I2C_MASK_STOP;             // STOP
            i2c_env.i2cOpFsm = I2C_OP_FINISH;
        }
        i2c_i2c_SetTXD(QN_I2C, reg);

    }

    if (status & I2C_MASK_TX_INT) {
        i2c_i2c_ClrIntStatus(QN_I2C, I2C_MASK_TX_INT);

        // check ack type
        if (i2c_i2c_GetSR(QN_I2C) & I2C_MASK_ACK_RECEIVED) { // NO ACK
            i2c_i2c_SetTXD(QN_I2C, I2C_MASK_STOP);           // STOP
            i2c_env.i2cOpFsm = I2C_OP_ABORT;
        }
        else { // ACK

            if (i2c_env.i2cOpFsm == I2C_OP_RDDATA) {  // enable data read
                if (i2c_env.i2cRxCount > 1) {
                    reg = I2C_MASK_RD_EN
                        | I2C_MASK_ACK_SEND;          // ACK
                }
                else if (i2c_env.i2cRxCount == 1) {
                    reg = I2C_MASK_RD_EN
                        | I2C_MASK_NACK_SEND;         // NACK
                }
                i2c_i2c_SetTXD(QN_I2C, reg);
            }
            else {
                if (i2c_env.i2cIndex < i2c_env.i2cTxCount) {
                    reg = I2C_MASK_WR_EN
                        | i2c_env.i2cBuffer[i2c_env.i2cIndex++];    // write address buffer
                    i2c_i2c_SetTXD(QN_I2C, reg);
                }
                else { // data tx finish, check need stop or not
                    if (i2c_env.i2cOpFsm == I2C_OP_WRDATA) {
                        i2c_i2c_SetTXD(QN_I2C, I2C_MASK_STOP);      // STOP
                        i2c_env.i2cOpFsm = I2C_OP_FINISH;
                    }
                    else if (i2c_env.i2cOpFsm == I2C_OP_SETADDR) {
                        //i2c_i2c_SetTXD(QN_I2C, I2C_MASK_STOP);
                        i2c_env.i2cOpFsm = I2C_OP_RDDATA;
                    }
                }
            }
        }
    }

}
Exemplo n.º 5
0
/**
 ****************************************************************************************
 * @brief Start a data reception.
 * @param[in]  saddr         slave device address(7bits, without R/W bit)
 * @return Error code
 * @description
 * This function is used to complete an I2C read transaction from start to stop. All the intermittent steps
 * are handled in the interrupt handler while the interrupt is enabled.
 * Before this function is called, the read length, write length, I2C master buffer,
 * and I2C state need to be filled. Please refer to I2C_BYTE_READ().
 * As soon as the end of the data transfer is detected, the callback function is called.
 *****************************************************************************************
 */
static enum I2C_ERR_CODE i2c_read(uint8_t saddr)
{
    uint32_t reg;
    uint32_t timeout = 0;

    if (i2c_bus_check() == I2C_BUS_BUSY) {
        return I2C_CONFLICT;
    }

    if (i2c_env.i2cTxCount) {
        i2c_env.i2cOpFsm = I2C_OP_SETADDR;
        // start write slave address with write bit
        reg = I2C_MASK_WR_EN
            | I2C_MASK_START
            | ((saddr << 1) & 0xFE);
        i2c_i2c_SetTXD(QN_I2C, reg);


        do {
            timeout++;
            if (timeout > I2C_MAX_TIMEOUT) {
                return I2C_TIMEOUT;
            }
#if CONFIG_I2C_ENABLE_INTERRUPT==FALSE
            i2c_polling();
#endif

            if (i2c_env.i2cOpFsm == I2C_OP_ABORT) {
                return I2C_NO_ACK;
            }

        } while (i2c_env.i2cOpFsm != I2C_OP_RDDATA);
    }
    else {
        // does not need write address, directly read data from device
        i2c_env.i2cOpFsm = I2C_OP_RDDATA;
    }
    
    // start write slave address with read bit
    reg = I2C_MASK_WR_EN
        | I2C_MASK_START
        | ((saddr << 1) | 0x01);
    i2c_i2c_SetTXD(QN_I2C, reg);

    timeout = 0;
    do {
        timeout++;
        if (timeout > I2C_MAX_TIMEOUT) {
            return I2C_TIMEOUT;
        }
#if CONFIG_I2C_ENABLE_INTERRUPT==FALSE
        i2c_polling();
#endif

        if (i2c_env.i2cOpFsm == I2C_OP_ABORT) {
            return I2C_NO_ACK;
        }

    } while (i2c_env.i2cOpFsm != I2C_OP_FINISH);

#if I2C_CALLBACK_EN==TRUE
    // Call end of reception callback
    if (i2c_env.callback != NULL)
    {
        i2c_env.callback();
    }
#endif

    return I2C_NO_ERROR;
}
Exemplo n.º 6
0
/**
 ****************************************************************************************
 * @brief Start a data reception.
 * @param[in]      saddr          slave device address (7bits, without R/W bit)
 * @description
 * This function is used to complete an I2C read transaction from start to stop. All the intermittent steps
 * are handled in the interrupt handler while the interrupt is enabled.
 * Before this function is called, the read length, write length, I2C master buffer,
 * and I2C state need to be filled. Please refer to I2C_BYTE_READ().
 * As soon as the end of the data transfer is detected, the callback function is called.
 *****************************************************************************************
 */
void i2c_read(uint8_t saddr)
{
    uint32_t reg;
    uint32_t timeout = 0;

    if (i2c_bus_check() == I2C_BUS_BUSY) {
        return;
    }

    if (i2c_env.i2cTxCount) {
        i2c_env.i2cOpFsm = I2C_OP_SETADDR;
        // start write slave address with write bit
        reg = I2C_MASK_WR_EN
            | I2C_MASK_START
            | ((saddr << 1) & 0xFE);
        i2c_i2c_SetTXD(QN_I2C, reg);

#ifdef SLP_TEST_EN
        // Wait For Interrupt
        __WFI();  // Enter sleep mode
        // Wakeup when I2C interrupt is triggered
#endif

        do {
            timeout++;
            if (timeout > I2C_MAX_TIMEOUT) {
                break;
            }
#if CONFIG_I2C_ENABLE_INTERRUPT==FALSE
            i2c_polling();
#endif
        } while ((i2c_env.i2cOpFsm != I2C_OP_RDDATA)&&(i2c_env.i2cOpFsm != I2C_OP_ABORT));
    }
    else {
        // does not need write address, directly read data from device
        i2c_env.i2cOpFsm = I2C_OP_RDDATA;
    }
    
    // start write slave address with read bit
    reg = I2C_MASK_WR_EN
        | I2C_MASK_START
        | ((saddr << 1) | 0x01);
    i2c_i2c_SetTXD(QN_I2C, reg);

    timeout = 0;
    do {
        timeout++;
        if (timeout > I2C_MAX_TIMEOUT){
            break;
        }
#if CONFIG_I2C_ENABLE_INTERRUPT==FALSE
        i2c_polling();
#endif
    } while (i2c_env.i2cOpFsm != I2C_OP_FINISH);

#if I2C_CALLBACK_EN==TRUE
    // Call end of reception callback
    if ((i2c_env.i2cOpFsm == I2C_OP_FINISH) && (i2c_env.callback != NULL))
    {
        i2c_env.callback();
    }
#endif

}