Beispiel #1
0
void i2c_handle_ev_interrupt(const _i2c_t *_i2c)
{
    _i2c_data_t *const data = _i2c->data;
    uint32_t sr1 = *i2c_get_SR1(_i2c);
    uint32_t sr2 = 0;
    (void) sr2; // clear defined but not used warning warning

    I2C_DEBUG_LOG(sr1, data->state, data->state == I2C_RECEIVING_DATA ? data->len_recv - data->cpt_recv : data->len_send - data->cpt_send);

    /*
     * EVxxx refer to the STM32 I2C datasheet's events
     *
     * STM32F1xx errata tells EV6_1 EV6_3 EV7 EV7_1 EV8 (and slave ones EV2 EV3)
     * should be handled before the current byte is transferred.
     * + EV6_1, EV6_3 must be un-interrupted
     * + EV8 must be done early enough
     * In consequence we mask TXBUFEN (RXNE and TXNE interrupt)
     */

    if (sr1 & I2C_SR1__SB)
    {
        // ** EV5 **
        // Start bit has been issued.
        // The flag is cleared after reading SR1 (already done at the
        // beginning of the function) and writing DR (done right now)

        // If there there is nothing to send, set the lower bit
        // of address to 1 as we are in receiving mode
        if (data->len_send == 0)
        {
            // Send address in order to receive data
            *i2c_get_DR(_i2c) = data->address | 1;

            // In the case of a 2-byte reception we need to set POS bit
            if (data->len_recv == 2)
            {
                *i2c_get_CR1(_i2c) |= I2C_CR1__POS;
            }
        }
        else
        {
            // Send address in order to send data
            *i2c_get_DR(_i2c) = data->address;
        }

        // Disable Buffer Interrupt
        *i2c_get_CR2(_i2c) &= ~I2C_CR2__ITBUFEN;

        // Enable ACK
        *i2c_get_CR1(_i2c) |= I2C_CR1__ACK;

        data->state = I2C_SENDING_ADDRESS;
    }

    if (sr1 & I2C_SR1__ADDR && data->state == I2C_SENDING_ADDRESS)
    {
        // ** EV6 **
        // Master mode: Address byte has been sent.
        // The flag is cleared after reading both SR1 and SR2

        // Send the first byte if any
        if (data->len_send > 0)
        {
            // Clear the flag by reading SR2. This must be done before sending data
            sr2 = *i2c_get_SR2(_i2c);

            // ** EV8_1 **
            // Send data
            *i2c_get_DR(_i2c) = data->buf_send[data->cpt_send];
            data->cpt_send++;

            if (data->cpt_send == data->len_send)
            {
                // ** EV8_2 **
                // The only byte to send has already been sent so we need to issue
                // a STOP condition if there is nothing to receive or
                // a RESTART condition otherwise
                if (data->len_recv == 0)
                {
                    // There is nothing to receive
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

                    // The transfer is complete
                    tx_rx_end(_i2c, I2C_IDLE);
                }
                else
                {
                    // We need to read something
                    *i2c_get_CR1(_i2c) |= I2C_CR1__START;

                    // Wait for the new start condition to be issued
                    data->state = I2C_SENDING_RESTART;
                }

                // Indicate that there is nothing else to send
                data->len_send = 0;
                data->cpt_send = 0;
            }
            else
            {
                // There is something else to send
                // Wait for the first byte to be sent
                data->state = I2C_SENDING_DATA;

                // STMF: do not enable ITBUFEN since we can not ensure
                // to handle EV8 before current byte transfer after TXNE
                // instead, we'll wait for BTF (which lower the transfer speed)
            }
        }
        else
        {
            switch (data->len_recv)
            {
                case 1:
                    // ** EV6_3 **
                    // STM32F_errata:
                    // + the sequence read_SR2 STOP should be fast enough
                    // + or SCL must be tied low in during it

                    // In this case we need to clear ACK bit right now
                    *i2c_get_CR1(_i2c) &= ~I2C_CR1__ACK;

                    // Clear the flag by reading SR2
                    sr2 = *i2c_get_SR2(_i2c);

                    // We also need to program the STOP condition
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

                    //activate ITBUFEN since we'll only receive a single byte
                    *i2c_get_CR2(_i2c) |= I2C_CR2__ITBUFEN;
                    break;

                case 2:
                    // ** EV6_1 **
                    // STM32F_errata:
                    // + the sequence read_SR2 NACK should be fast enough
                    // + or SCL must be tied low in during it

                    // Clear the flag by reading SR2
                    sr2 = *i2c_get_SR2(_i2c);

                    // Clear ACK bit
                    *i2c_get_CR1(_i2c) &= ~I2C_CR1__ACK;
                    break;

                default:
                    // In the default case we do not need to do anything
                    // except clearing the flag by reading SR2
                    sr2 = *i2c_get_SR2(_i2c);
                    break;
            }

            // Wait for the first byte to read
            data->state = I2C_RECEIVING_DATA;
        }

        // return there
        // in particular, we must not execute TXNE part because
        // we may have written into DR
        return;
    }
#ifdef I2C__SLAVE_SUPPORT
    else if (sr1 & I2C_SR1__ADDR && (data->state == I2C_IDLE ||
                (data->state == I2C_SL_RX && !(sr1 & I2C_SR1__RXNE))))
    {
        // ** EV1 **
        // Slave mode: Address byte has been acknowledged.

        // Clear the flag by reading SR2.
        sr2 = *i2c_get_SR2(_i2c);

        // Disable Buffer Interrupt
        *i2c_get_CR2(_i2c) &= ~I2C_CR2__ITBUFEN;

        if (sr2 & I2C_SR2__TRA)
        {
            uint8_t byte = 0;
            // we will send data
            data->state = I2C_SL_TX;
            if (data->slave_handler)
            {
                data->slave_handler(I2C_SLAVE_EV_TX_START, NULL);
                data->slave_handler(I2C_SLAVE_EV_TX_BYTE, &byte);
            }

            //send the first byte
            *i2c_get_DR(_i2c) = byte;
        }
        else
        {
            // we will receive data
            data->state = I2C_SL_RX;
            if (data->slave_handler)
            {
                data->slave_handler(I2C_SLAVE_EV_RX_START, NULL);
            }
        }

        return;
    }
#endif

    if (sr1 & I2C_SR1__ADD10)
    {
        // This should not happen as we do not handle 10-bits addresses
        log_error("ADD10 interrupt!");

        // Set stop bit to stop transfer
        *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

        // Update State
        tx_rx_end(_i2c, I2C_ERROR);
        return;
    }

    if (sr1 & I2C_SR1__RXNE)
    {
        /* Note:
         *  when RXNE:
         *     + 1 byte is in I2C controller buffers
         *     + bus is not stalled (one byte may be in transfer)
         *  when BTF & RXNE:
         *     + 2 bytes are in I2C controller buffers
         *     + bus is stalled (controller wait we read a byte)
         */
        if (data->state == I2C_RECEIVING_DATA)
        {
            /* * * * * * * WARNING STM32F1xx HARDWARE ERRATA * * * * * * *
             * RXNE-only events should not be handled since it sometimes *
             * fails. Only BTF & RXNE events should be handled (with the *
             * consequence of slowing down the transfer).                *
             *                                                           *
             * It seems that when a RXNE interrupt is handled 'around'   *
             * the end of the next byte reception, the DR register read  *
             * is ignored by the i2c controller: it does not flush the   *
             * DR with next byte                                         *
             * Thus we read twice the same byte and we read effectively  *
             * read one byte less than expected from the i2c slave point *
             * of view.                                                  *
             * Example:                                                  *
             *  + we want to receive 6 bytes (B1 to B6)                  *
             *  + the problem appear when reading B3                     *
             *  -> we read B1 B2 B3 B3 B4 B5 (B3 twice)                  *
             *  -> the i2c transfer was B1 B2 B3 B4 B5 (B6 is not sent)  *
             * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
            int remaining = data->len_recv - data->cpt_recv;
            if (remaining <= 0)
            {
                //should not happen
                log_error("Bad I2C receiving state");
                *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;
                *i2c_get_DR(_i2c);
                *i2c_get_DR(_i2c);
                tx_rx_end(_i2c, I2C_ERROR);
            }
            else
            {
                switch (remaining)
                {
                    default:// >=4
                        if (sr1 & I2C_SR1__BTF)
                        {
                            // ** EV7 **
                            // Read the byte that is in buffer
                            data->buf_recv[data->cpt_recv++] = *i2c_get_DR(_i2c);
                        }
                        break;

                    case 3:
                        // Bytes 1..N-3 have been read
                        if (sr1 & I2C_SR1__BTF)
                        {
                            // ** EV7 **
                            // Bytes N-2 and N-1 have been received

                            // Program NACK
                            *i2c_get_CR1(_i2c) &= ~I2C_CR1__ACK;
                            // Read N-3 to ensure BTF after N (before STOP)
                            data->buf_recv[data->cpt_recv++] = *i2c_get_DR(_i2c);
                        }
                        break;

                    case 2:
                        // Bytes 1..N-2 have been read
                        if (sr1 & I2C_SR1__BTF)
                        {
                            // ** (EV7_1 and EV7) or EV7_3 **
                            // STM32F_errata:
                            // + the sequence STOP read_DR read_DR should be fast enough
                            // + or SCL must be tied low in during it

                            // Program STOP
                            *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;
                            // Read N-2
                            data->buf_recv[data->cpt_recv++] = *i2c_get_DR(_i2c);
                            // Read N-1
                            data->buf_recv[data->cpt_recv++] = *i2c_get_DR(_i2c);

                            // Indicate that there is nothing else to receive
                            data->len_recv = 0;
                            data->cpt_recv = 0;
                            // Signal the transfer is complete
                            tx_rx_end(_i2c, I2C_IDLE);
                        }
                        break;

                    case 1:
                        // ** EV7 **
                        // Happen only on single byte transfers
                        // The byte has been received but not read
                        // Note: BTF should not be set
                        data->buf_recv[data->cpt_recv++] = *i2c_get_DR(_i2c);

                        // Indicate that there is nothing else to receive
                        data->len_recv = 0;
                        data->cpt_recv = 0;

                        // The transfer is complete
                        tx_rx_end(_i2c, I2C_IDLE);
                        break;
                }
            }
        }
#ifdef I2C__SLAVE_SUPPORT
        else if (data->state == I2C_SL_RX)
        {
            if (sr1 & I2C_SR1__BTF || ((sr1 & I2C_SR1__ADDR) && (sr1 & I2C_SR1__TXE)))
            {
                // ** EV2 **
                // read the byte into the buffer
                uint8_t byte = *i2c_get_DR(_i2c);
                data->slave_handler(I2C_SLAVE_EV_RX_BYTE, &byte);
            }
        }
#endif
    }

    if (sr1 & I2C_SR1__TXE)
    {
        // The flag is cleared after reading SR1 (already done) and reading or writing DR
        if (data->state == I2C_SENDING_DATA)
        {
            if (data->len_send == data->cpt_send)
            {
                // ** EV8_2 **
                // The last byte has been sent so we need to issue
                // a STOP condition if there is nothing to receive or
                // a RESTART condition otherwise

                if (data->len_recv == 0)
                {
                    // There is nothing to receive
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

                    // The transfer is complete
                    tx_rx_end(_i2c, I2C_IDLE);
                }
                else
                {
                    // We need to read something
                    *i2c_get_CR1(_i2c) |= I2C_CR1__START;

                    data->state = I2C_SENDING_RESTART;
                }

                // Indicate that there is nothing else to send
                data->len_send = 0;
                data->cpt_send = 0;
            }
            else
            {
                // ** EV8 **
                // Send the data
                *i2c_get_DR(_i2c) = data->buf_send[data->cpt_send];
                data->cpt_send++;

                // Stay in the I2C_SENDING_DATA state
            }
        }
#ifdef I2C__SLAVE_SUPPORT
        else if (data->state == I2C_SL_TX)
        {
            // ** EV3 **
            uint8_t byte;
            // request the byte to send
            data->slave_handler(I2C_SLAVE_EV_TX_BYTE, &byte);
            *i2c_get_DR(_i2c) = byte;
        }
#endif
    }


    if (sr1 & I2C_SR1__STOPF)
    {
        switch (data->state)
        {
#ifdef I2C__SLAVE_SUPPORT
            case I2C_SL_RX:
                if (sr1 & I2C_SR1__RXNE)
                {
                    // it remains exactly 1 byte to read
                    // since we have already read the buffer one (if any)
                    uint8_t byte = *i2c_get_DR(_i2c);
                    if (data->slave_handler)
                    {
                        data->slave_handler(I2C_SLAVE_EV_RX_BYTE, &byte);
                    }
                }
                sr1 = *i2c_get_SR1(_i2c);
                *i2c_get_CR1(_i2c) &= ~I2C_CR1__STOP;
                data->state = I2C_IDLE;
                if (data->slave_handler)
                {
                    data->slave_handler(I2C_SLAVE_EV_STOP, NULL);
                }
                break;
            case I2C_SL_TX:
                log_error("STOPF interrupt!");
                data->state = I2C_IDLE;
                break;
#endif
            default:
                // This should not happen as we are in master mode
                log_error("STOPF interrupt!");
                uint8_t x = *i2c_get_CR1(_i2c);
                *i2c_get_CR1(_i2c) = x;

                // Set stop bit to stop transfer
                *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

                // Update State
                tx_rx_end(_i2c, I2C_ERROR);
                break;
        }
    }
}
Beispiel #2
0
void i2c_handle_ev_interrupt(_i2c_t *_i2c)
{
    uint32_t sr1 = *i2c_get_SR1(_i2c);
    uint32_t sr2 = 0;
    (void)sr2; // clear defined but not used warning warning 

    if (sr1 & I2C_SR1__SB)
    {
        // Start bit has been issued.
        // The flag is cleared after reading SR1 (already done at the
        // beginning of the function) and writing DR (done right now)

        // If there there is nothing to send, set the lower bit
        // of address to 1 as we are in receiving mode
        if (len_send == 0)
        {
            // Send address in order to receive data
            *i2c_get_DR(_i2c) = address | 1;

            // In the case of a 2-byte reception we need to set POS bit
            if (len_recv == 2)
            {
                *i2c_get_CR1(_i2c) |= I2C_CR1__POS;
            }
        }
        else
        {
            // Send address in order to send data
            *i2c_get_DR(_i2c) = address;
        }

        *i2c_get_CR1(_i2c) |= I2C_CR1__ACK;

        state = I2C_SENDING_ADDRESS;
    }

    if (sr1 & I2C_SR1__ADDR)
    {
        // Address byte has been sent.
        // The flag is cleared after reading both SR1 and SR2

        // Send the first byte if any
        if (len_send > 0)
        {
            // Clear the flag by reading SR2. This must be done before sending data
            sr2 = *i2c_get_SR2(_i2c);

            // Send data
            *i2c_get_DR(_i2c) = buf_send[cpt_send];
            cpt_send++;

            if (cpt_send == len_send)
            {
                // The only byte to send has already been sent so we need to issue
                // a STOP condition if there is nothing to receive or
                // a RESTART condition otherwise
                if (len_recv == 0)
                {
                    // There is nothing to receive
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

                    // The transfer is complete
                    state = I2C_IDLE;
                }
                else
                {
                    // We need to read something
                    *i2c_get_CR1(_i2c) |= I2C_CR1__START;

                    // Wait for the new start condition to be issued
                    state = I2C_SENDING_RESTART;
                }

                // Indicate that there is nothing else to send
                len_send = 0;
                cpt_send = 0;
            }
            else
            {
                // There is something else to send
                // Wait for the first byte to be sent
                state = I2C_SENDING_DATA;
            }
        }
        else
        {
            switch (len_recv)
            {
                case 1:
                    // In this case we need to clear ACK bit right now
                    *i2c_get_CR1(_i2c) &= ~I2C_CR1__ACK;

                    // Clear the flag by reading SR2
                    sr2 = *i2c_get_SR2(_i2c);

                    // We also need to program the STOP condition
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;
                    break;

                case 2:
                    // Clear the flag by reading SR2
                    sr2 = *i2c_get_SR2(_i2c);

                    // Clear ACK bit
                    *i2c_get_CR1(_i2c) &= ~I2C_CR1__ACK;
                    break;

                default:
                    // In the default case we do not need to do anything
                    // except clearing the flag by reading SR2
                    sr2 = *i2c_get_SR2(_i2c);
            }

            // Wait for the first byte to read
            state = I2C_RECEIVING_DATA;
        }
    }

    if (sr1 & I2C_SR1__BTF)
    {
        // This is the only case where we need BTF flag
        // We have waited until the last two bytes to read are available
        if ((state == I2C_RECEIVING_DATA) && (len_recv == 2))
        {
            // Program a STOP condition before reading the second last data
            *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

            // Read Data[N-1]
            buf_recv[cpt_recv] = *i2c_get_DR(_i2c);
            cpt_recv++;

            // Read Data[N]
            buf_recv[cpt_recv] = *i2c_get_DR(_i2c);
            cpt_recv++;

            // Unset POS bit in order not disturb next transfers
            *i2c_get_CR1(_i2c) &= ~I2C_CR1__POS;

            // Goto idle state
            state = I2C_IDLE;
        }
    }

    if (sr1 & I2C_SR1__ADD10)
    {
        // This should not happen as we do not handle 10-bits addresses
        log_error("ADD10 interrupt!");
    }

    if (sr1 & I2C_SR1__STOPF)
    {
        // This should not happen as we are in master mode
        log_error("STOPF interrupt!");
    }

    // The following two cases should not happen as ITBUFEN is not set

    if (sr1 & I2C_SR1__RXNE)
    {
        if (state == I2C_RECEIVING_DATA)
        {
            // We are receiving data
            if (len_recv == 1)
            {
                // This is the only byte to read
                buf_recv[cpt_recv] = *i2c_get_DR(_i2c);

                // Indicate that there is nothing else to receive
                len_recv = 0;
                cpt_recv = 0;

                // The transfer is complete
                state = I2C_IDLE;
            }
            else if (len_recv == 2)
            {
                // Do not read yet, wait for BTF to be issued

                // Stay in the I2C_RECEIVING_DATA state
            }
            else
            {
                // Read data
                buf_recv[cpt_recv] = *i2c_get_DR(_i2c);
                cpt_recv++;

                if (len_recv - cpt_recv == 1)
                {
                    // We need to clear ACK bit to be sure NACK is sent when the last data is received
                    *i2c_get_CR1(_i2c) &= ~I2C_CR1__ACK;

                    // Program a STOP condition before reading the second last data
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;
                }

                if (len_recv == cpt_recv)
                {
                    state = I2C_IDLE;
                }

                // Else stay in the I2C_RECEIVING_DATA state
            }

            // In other cases there is nothing to do
        }
        else
        {
            // This flag should not be set when we are not in receiving mode
            (void)(*i2c_get_DR(_i2c));
        }
    }

    if (sr1 & I2C_SR1__TXE)
    {
        // The flag is cleared after reading SR1 (already done) and reading or writing DR
        if (state == I2C_SENDING_DATA)
        {
            if (len_send == cpt_send)
            {
                // The last byte has been sent so we need to issue
                // a STOP condition if there is nothing to receive or
                // a RESTART condition otherwise
                if (len_recv == 0)
                {
                    // There is nothing to receive
                    *i2c_get_CR1(_i2c) |= I2C_CR1__STOP;

                    // The transfer is complete
                    state = I2C_IDLE;
                }
                else
                {
                    // We need to read something
                    *i2c_get_CR1(_i2c) |= I2C_CR1__START;

                    state = I2C_SENDING_RESTART;
                }

                // Indicate that there is nothing else to send
                len_send = 0;
                cpt_send = 0;
            }
            else
            {
                // Send the data
                *i2c_get_DR(_i2c) = buf_send[cpt_send];
                cpt_send++;

                // Stay in the I2C_SENDING_DATA state
            }
        }

        // If we are not sending data, do nothing
    }
}