1.7. 通信接口

F28335 提供 SCI (UART)、SPI、I2C 和 eCAN 等通信接口。

1.7.1. SCI (UART)

SCI 是异步串行接口,支持 RS232/RS485。

void SciA_Init(void)
{
    // 配置 GPIO(使用功能 1)
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO28 = 1;  // SCIRXDA
    GpioCtrlRegs.GPAMUX1.bit.GPIO29 = 1;  // SCITXDA
    EDIS;

    // SCI 配置:115200, 8N1
    SciaRegs.SCICCR.all = 0x0007;   // 8 位, 无校验, 1 停止位
    SciaRegs.SCICTL1.all = 0x0003;  // 使能 TX, RX
    SciaRegs.SCICTL2.bit.TXINTENA = 1;
    SciaRegs.SCICTL2.bit.RXBKINTENA = 1;

    // 波特率 = LSPCLK / (BRR + 1) × 8
    // 115200 = 37.5e6 / (BRR + 1) × 8
    // BRR ≈ 39
    SciaRegs.SCIHBAUD = 0x0000;
    SciaRegs.SCILBAUD = 39;         // 115200 baud

    SciaRegs.SCICTL1.all = 0x0023;  // 退出复位
}
// 发送字符
void SciA_SendChar(char data)
{
    while (SciaRegs.SCICTL2.bit.TXRDY == 0) { }  // 等待 TX 缓冲区空
    SciaRegs.SCITXBUF = data;
}

// 发送字符串
void SciA_SendString(const char *str)
{
    while (*str) {
        SciA_SendChar(*str++);
    }
}

// 接收字符(中断方式)
interrupt void scia_rx_isr(void)
{
    uint16_t received = SciaRegs.SCIRXBUF.all;  // 读取数据

    // 处理接收到的数据
    rx_buffer[rx_index++] = received & 0xFF;

    // 清除标志
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}

1.7.2. SPI

void SpiA_Init(void)
{
    // GPIO 配置
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO16 = 1;  // SPISIMO
    GpioCtrlRegs.GPAMUX1.bit.GPIO17 = 1;  // SPISOMI
    GpioCtrlRegs.GPAMUX1.bit.GPIO18 = 1;  // SPICLK
    GpioCtrlRegs.GPAMUX1.bit.GPIO19 = 1;  // SPISTE(片选)
    EDIS;

    // SPI 配置
    SpiaRegs.SPICCR.all = 0x000F;    // 16 位数据, 上升沿
    SpiaRegs.SPICTL.all = 0x0006;    // 主模式, 使能 TX
    SpiaRegs.SPIBRR = 0x004E;        // 波特率 = LSPCLK / (BRR+1)
    SpiaRegs.SPICCR.all = 0x009F;    // 退出复位, 16 位

    // 片选控制 (GPIO19 作为 SPI STE)
    SpiaRegs.SPICTL.bit.SPIINTENA = 0;  // 暂不使用中断
}

uint16_t SpiA_Transfer(uint16_t data)
{
    SpiaRegs.SPITXBUF = data;            // 发送
    while (SpiaRegs.SPISTS.bit.INT_FLAG == 0) { }  // 等待完成
    return SpiaRegs.SPIRXBUF;            // 返回接收数据
}

// SPI 写入 DAC 示例
void SpiA_WriteDAC(uint16_t channel, uint16_t value)
{
    uint16_t cmd = (channel << 15) | (value & 0x0FFF);
    SpiaRegs.SPITXBUF = cmd;
    while (SpiaRegs.SPISTS.bit.INT_FLAG == 0) { }
    SpiaRegs.SPIRXBUF;  // 读取清除标志
}

1.7.3. I2C

void I2cA_Init(void)
{
    // GPIO 配置
    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO32 = 1;  // SDAA
    GpioCtrlRegs.GPAMUX1.bit.GPIO33 = 1;  // SCLA
    EDIS;

    // I2C 配置
    I2caRegs.I2CSAR = 0x0050;       // 从机地址 (7-bit)
    I2caRegs.I2CCLKL = 60;          // SCL 低电平计数
    I2caRegs.I2CCLKH = 60;          // SCL 高电平计数
    // I2C 频率 = LSPCLK / (I2CCLKL + I2CCLKH + 6)
    // 100 kHz = 37.5e6 / (60 + 60 + 6)
    I2caRegs.I2CPSC = 18;           // 预分频 = LSPCLK / (PSC+1)
    I2caRegs.I2CMDR.bit.IRS = 1;    // 退出复位
}

void I2cA_WriteByte(uint16_t reg, uint16_t data)
{
    // 等待总线空闲
    while (I2caRegs.I2CSTR.bit.BB == 1) { }

    I2caRegs.I2CSAR = 0x50;          // 从机地址
    I2caRegs.I2CCNT = 2;             // 发送 2 字节(寄存器+数据)
    I2caRegs.I2CDXR = reg;           // 寄存器地址
    I2caRegs.I2CDXR = data;          // 数据

    I2caRegs.I2CMDR.all = 0x0620;    // 主发模式, 起始位, 停止位
    while (I2caRegs.I2CSTR.bit.SCD == 0) { }  // 等待停止位
    I2caRegs.I2CSTR.bit.SCD = 1;     // 清除标志
}

1.7.4. eCAN

void CAN_Init(void)
{
    EALLOW;
    GpioCtrlRegs.GPAMUX2.bit.GPIO34 = 1;  // CANTXB
    GpioCtrlRegs.GPAMUX2.bit.GPIO35 = 1;  // CANRXB
    EDIS;

    // 初始化 eCAN
    ECanaRegs.CANMC.bit.SCB = 1;      // 使能 eCAN 模式
    ECanaRegs.CANMC.bit.ABO = 1;      // 自动恢复(总线关闭后)
    ECanaRegs.CANBTC.bit.BRPREG = 4;  // 波特率预分频
    ECanaRegs.CANBTC.bit.TSEG2REG = 2;
    ECanaRegs.CANBTC.bit.TSEG1REG = 5;
    // 波特率 = SYSCLKOUT / ((BRPREG+1) × (TSEG1+ TSEG2+1))
    // 500 kbps = 150 MHz / (5 × (5+2+1) × 2)

    ECanaRegs.CANMC.bit.CCR = 1;      // 进入配置模式
    while (ECanaRegs.CANES.bit.CCE != 1) { }
    ECanaRegs.CANMC.bit.CCR = 0;      // 退出配置模式
    while (ECanaRegs.CANES.bit.CCE == 1) { }
}

void CAN_SendMessage(uint32_t id, uint16_t *data, uint8_t len)
{
    // 等待邮箱就绪
    while (ECanaRegs.CANTRS.all != 0) { }

    ECanaMboxes.MBOX0.MSGID.all = id & 0x1FFFFFFF;
    ECanaMboxes.MBOX0.MSGCTRL.all = 0;

    // 复制数据
    for (int i = 0; i < len; i++) {
        ECanaMboxes.MBOX0.MDR[i].all = data[i];
    }

    ECanaRegs.CANTRS.bit.TRS0 = 1;   // 请求发送
}

小技巧

CAN 总线常用于电机驱动和工业控制: - 500 kbps:最长 250 米 - 250 kbps:最长 500 米 - 125 kbps:最长 1000 米