STM32F40x 芯片的 I2C 外设没有 r/w 位可供固件使用

No r/w bit made available to firmware by I2C peripheral of STM32F40x chips

我想知道是否有人找到了一种方法来确定主机与 stm32f40x 芯片通信的意图?从stm32f40x芯片上的固件来看,master发送的ADDRess是不可用的,其中包含的r/w位(地址的第0位)也不可用。那么如何防止碰撞呢?还有其他人处理过这个吗?如果是这样,你使用了什么技术?我的暂定方案如下,供参考。我延迟了对 DR 数据寄存器的任何写入,直到发生 TXE 中断。一开始我以为这会太晚了,一个字节的垃圾会被计时,但它似乎在工作。

static inline void LLEVInterrupt(uint16_t irqSrc)
{
    uint8_t  i;
    volatile uint16_t status;
    I2CCBStruct* buffers;
    I2C_TypeDef* addrBase;

    // see which IRQ occurred, process accordingly...
    switch (irqSrc)
    {
        case I2C_BUS_CHAN_1:
            addrBase = this.addrBase1;
            buffers = &this.buffsBus1;
            break;
        case I2C_BUS_CHAN_2:
            addrBase = this.addrBase2;
            buffers = &this.buffsBus2;
            break;
        case I2C_BUS_CHAN_3:
            addrBase = this.addrBase3;
            buffers = &this.buffsBus3;
            break;
        default:
            while(1);
    }

    // ...START condition & address match detected
    if (I2C_GetITStatus(addrBase, I2C_IT_ADDR) == SET)
    {
        // I2C_IT_ADDR: Cleared by software reading SR1 register followed reading SR2, or by hardware
        //  when PE=0.
        // Note: Reading I2C_SR2 after reading I2C_SR1 clears the ADDR flag, even if the ADDR flag was
        //  set after reading I2C_SR1. Consequently, I2C_SR2 must be read only when ADDR is found
        //  set in I2C_SR1 or when the STOPF bit is cleared.
        status = addrBase->SR1;
        status = addrBase->SR2;

        // Reset the index and receive count
        buffers->txIndex = 0;
        buffers->rxCount = 0;

        // setup to ACK any Rx'd bytes
        I2C_AcknowledgeConfig(addrBase, ENABLE);
        return;
    }

    // Slave receiver mode
    if (I2C_GetITStatus(addrBase, I2C_IT_RXNE) == SET)
    {
        // I2C_IT_RXNE: Cleared by software reading or writing the DR register 
        //  or by hardware when PE=0.

        // copy the received byte to the Rx buffer
        buffers->rxBuf[buffers->rxCount] = (uint8_t)I2C_ReadRegister(addrBase, I2C_Register_DR);
        if (RX_BUFFER_SIZE > buffers->rxCount)
        {
            buffers->rxCount++;
        }
        return;
    }

    // Slave transmitter mode
    if (I2C_GetITStatus(addrBase, I2C_IT_TXE) == SET)
    {
        // I2C_IT_TXE: Cleared by software writing to the DR register or 
        //  by hardware after a start or a stop condition or when PE=0.

        // send any remaining bytes
        I2C_SendData(addrBase, buffers->txBuf[buffers->txIndex]);
        if (buffers->txIndex < buffers->txCount)
        {
            buffers->txIndex++;
        }
        return;
    }

    // ...STOP condition detected
    if (I2C_GetITStatus(addrBase, I2C_IT_STOPF) == SET)
    {
        // STOPF (STOP detection) is cleared by software sequence: a read operation 
        //  to I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to 
        //  I2C_CR1 register (I2C_Cmd() to re-enable the I2C peripheral).
        // From the reference manual RM0368:
        // Figure 163. Transfer sequence diagram for slave receiver
        // if (STOPF == 1) {READ SR1; WRITE CR1}
        // clear the IRQ status
        status = addrBase->SR1;
        // Write to CR1
        I2C_Cmd(addrBase, ENABLE);

        // read cycle (reset the status?
        if (buffers->txCount > 0)
        {
            buffers->txCount = 0;
            buffers->txIndex = 0;
        }

        // write cycle begun?
        if (buffers->rxCount > 0)
        {
            // pass the I2C data to the enabled protocol handler
            for (i = 0; i < buffers->rxCount; i++)
            {
                #if (COMM_PROTOCOL == COMM_PROTOCOL_DEBUG)
                 status = ProtProcRxData(buffers->rxBuf[i]);
                #elif (COMM_PROTOCOL == COMM_PROTOCOL_PTEK)
                 status = PTEKProcRxData(buffers->rxBuf[i]);
                #else
                 #error ** Invalid Host Protocol Selected **
                #endif
                if (status != ST_OK)
                {
                    LogErr(ST_COMM_FAIL, __LINE__);
                }
            }
            buffers->rxCount = 0;
        }
        return;
    }

    if (I2C_GetITStatus(addrBase, I2C_IT_AF) == SET)
    {
        // The NAck received from the host on the last byte of a transmit 
        //  is shown as an acknowledge failure and must be cleared by 
        //  writing 0 to the AF bit in SR1.
        // This is not a real error but just how the i2c slave transmission process works.
        // The hardware has no way to know how many bytes are to be transmitted, so the 
        //  NAck is assumed to be a failed byte transmission.
        // EV3-2: AF=1; AF is cleared by writing ‘0’ in AF bit of SR1 register.
        I2C_ClearITPendingBit(addrBase, I2C_IT_AF);
        return;
    }

    if (I2C_GetITStatus(addrBase, I2C_IT_BERR) == SET)
    {
        // There are extremely infrequent bus errors when testing with I2C Stick.
        // Safer to have this check and clear than to risk an 
        //  infinite loop of interrupts
        // Set by hardware when the interface detects an SDA rising or falling 
        //  edge while SCL is high, occurring in a non-valid position during a 
        //  byte transfer.
        // Cleared by software writing 0, or by hardware when PE=0.
        I2C_ClearITPendingBit(addrBase, I2C_IT_BERR);
        LogErr(ST_COMM_FAIL, __LINE__);
        return;
    }

    if (I2C_GetITStatus(addrBase, I2C_IT_OVR) == SET)
    {
        // Check for other errors conditions that must be cleared.
        I2C_ClearITPendingBit(addrBase, I2C_IT_OVR);
        LogErr(ST_COMM_FAIL, __LINE__);
        return;
    }

    if (I2C_GetITStatus(addrBase, I2C_IT_TIMEOUT) == SET)
    {
        // Check for other errors conditions that must be cleared.
        I2C_ClearITPendingBit(addrBase, I2C_IT_TIMEOUT);
        LogErr(ST_COMM_FAIL, __LINE__);
        return;
    }

    // a spurious IRQ occurred; log it
    LogErr(ST_INV_STATE, __LINE__);
}

我不确定我是否理解你。关于您想做什么,您是否应该提供更多信息或示例。

也许这有帮助: 我的经验是,在许多 I2C 实现中,R/W-Bit 与 7 位地址一起使用,因此大多数时候,没有额外的功能来设置或重置 R/W-Bit。

也就是说,所有超过128的地址都应该用来从从机读取数据,所有超过127的地址都应该用来向从机写入数据。

似乎无法确定由收到地址发起的事务是读取还是写入,即使硬件知道 LSbit 是已设置还是已清除。 master 的意图只有在 RXNE 或 TXE interrupt/bit 发生后才能知道。