7

CH32V003 I2C 从机实现

 1 year ago
source link: https://www.taterli.com/9272/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

CH32V003 I2C 从机实现

CH32V003 I2C 从机实现

很多厂商,特别是国内的,对I2C从机的实现基本都不怎么在意,但是平时我又很多时候要让单片机做从机,一些简单的低数据量的交互非常方便.而且不额外占用任何IO.

时序分析是写代码的关键,幸好,在文档中有描述.

image-1.png
image-2.png

首先第一个共同的地方,EVT1,即ADDR匹配,但是一般的I2C通信是包含寄存器+内容的,所以更多的是类似如下的时序.

image-3.png

所以第二触发一定是EVT2(写寄存器地址),如果EVT2发生后,继续发生EVT2,可以理解成写入寄存器,则每次写入,寄存器指针移动1,如果检查到START标志(EVT1),则其实是RESTART,这时候读写方向就反了.

清除标志时候比较特别,基本上每种标志都有自己的清除方法,还真的挺混乱,还有就是收到STOP或者其他不明条件,就要马上停止,免得从机锁死总线.

标志解释:

  • I2C_FLAG_ADDR 地址匹配,可能是首次匹配,RESTART匹配,根据状态机分析.
  • I2C_FLAG_STOPF 收到停止信号,主机强制释放总线等.
  • I2C_FLAG_RXNE 收到主机送过来数据.
  • I2C_FLAG_TXE 主机等着给他送数据.
  • I2C_FLAG_AF 送数据给主机过程中的最后一个数据(NAK).

代码实现,对状态机进行了简化,因此实际代码并不多,更多功能就自己想了.

#include "debug.h"

uint8_t reg_index = 0;
uint8_t reg[255] = {0x00};

#define DEVICE_IDLE 0
#define DEVICE_EVT1 1
#define DEVICE_EVT2 2

void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void I2C1_EV_IRQHandler(void)
{
    static uint8_t evt = DEVICE_IDLE;

    if(evt == DEVICE_IDLE){
        if(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR)){
            (void)(I2C1->STAR2);
            evt = DEVICE_EVT1;
        }else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)){
            I2C1->CTLR1 &= I2C1->CTLR1;
        }
    }else if(evt == DEVICE_EVT1){
        if(I2C_GetFlagStatus( I2C1, I2C_FLAG_RXNE )){
            reg_index = I2C_ReceiveData(I2C1);
            evt = DEVICE_EVT2;
        }else{
            evt = DEVICE_IDLE;
        }
    }else if(evt == DEVICE_EVT2){
        if(I2C_GetFlagStatus( I2C1, I2C_FLAG_RXNE )){
            reg[reg_index] = I2C_ReceiveData(I2C1);
            reg_index++;
        }else if(I2C_GetFlagStatus( I2C1, I2C_FLAG_TXE)){
            I2C_SendData(I2C1, reg[reg_index]);
            reg_index++;
        }else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF)){
            I2C_SendData(I2C1, reg[reg_index]);
            reg_index++;
            I2C1->STAR1 &= ~I2C_FLAG_AF;
            evt = DEVICE_IDLE;
        }else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR)){
            (void)(I2C1->STAR2);
        }else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)){
            I2C1->CTLR1 &= I2C1->CTLR1;
            evt = DEVICE_IDLE;
        }
    }
}

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure={0};
    I2C_InitTypeDef I2C_InitTSturcture={0};
    NVIC_InitTypeDef NVIC_InitStructure = {0};

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE );
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // SCL
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOC, &GPIO_InitStructure );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // SDA
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOC, &GPIO_InitStructure );

    NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    I2C_InitTSturcture.I2C_ClockSpeed = 100000;
    I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
    I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9;
    I2C_InitTSturcture.I2C_OwnAddress1 = 0x90;
    I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
    I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init( I2C1, &I2C_InitTSturcture );

    I2C_ITConfig(I2C1,I2C_IT_BUF,ENABLE);
    I2C_ITConfig(I2C1,I2C_IT_EVT,ENABLE);

    NVIC_EnableIRQ(I2C1_EV_IRQn);

    I2C_Cmd( I2C1, ENABLE );

    while(1);
}

其实这个芯片功能还算齐全,便宜,但是资料是真的很杂乱,但是看在价格份上,不得不原谅呢.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK