kehuadong

模拟SPI

#include "mcu_io.h"
#include "mcu_timer.h"

#include "mcu_spi.h"

void mcu_spi_init(mcu_spi_t* spi, uint8_t cs_pin, uint8_t clk_pin, uint8_t mosi_pin, uint8_t miso_pin, uint8_t mode, uint8_t speed, bool msb)
{
    spi->m_cs_pin   = cs_pin;
    spi->m_clk_pin  = clk_pin;
    spi->m_mosi_pin = mosi_pin;
    spi->m_miso_pin = miso_pin;
    spi->m_mode     = mode;
    spi->m_msb      = msb;

    switch (speed)
    {
        case MCU_SPI_SPEED_200K: spi->m_wait_step = 10;     break;
        case MCU_SPI_SPEED_400K: spi->m_wait_step = 2;      break;
        case MCU_SPI_SPEED_1M:   spi->m_wait_step = 0;      break;
        default: spi->m_wait_step = 28;     break;
    }

    mcu_io_set_mode(cs_pin, MCU_IO_MODE_OUTPUT);
    mcu_io_set_mode(clk_pin, MCU_IO_MODE_OUTPUT);
    mcu_io_set_mode(mosi_pin, MCU_IO_MODE_OUTPUT);
    mcu_io_set_mode(miso_pin, MCU_IO_MODE_INPUT);

    mcu_io_set_state(cs_pin, true);
}


void mcu_spi_transfer(mcu_spi_t* spi, uint8_t* tx, uint8_t* rx, uint16_t len)
{
    uint8_t clk_pin     = spi->m_clk_pin;
    uint8_t mosi_pin    = spi->m_mosi_pin;
    uint8_t miso_pin    = spi->m_miso_pin;
    uint16_t wait_step  = spi->m_wait_step;

    static const uint8_t LSB_MASK[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
    static const uint8_t MSB_MASK[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};

    const uint8_t* mask = (spi->m_msb ? MSB_MASK : LSB_MASK);
    
    // 时钟极性(用来指示拉低片选时的状态)
    uint8_t clk_init_state = (spi->m_mode&0x02) != 0;
    mcu_io_set_state(clk_pin, clk_init_state);

    // 片选
    mcu_io_set_state(spi->m_cs_pin, false);

    // 相位(用来表示以后要移动半个周期)
    if ((spi->m_mode&0x01) != 0)
    {
        mcu_timer_wait_step(wait_step);
        clk_init_state = !clk_init_state;
        mcu_io_set_state(clk_pin, clk_init_state);
    }
    
    // 数据交换
    for (uint16_t i = 0; i < len; i++)
    {
        uint8_t ch = 0xFF;

        if (tx)
        {
            ch = tx[i];
        }

        if (rx)
        {
            rx[i] = 0;
        }
        
        for (uint8_t j = 0; j < 8; j++)
        {
            // 周期开始后马上写入
            mcu_io_set_state(mosi_pin, (ch&mask[j]) != 0);
            
            // 前半个周期的等待
            mcu_timer_wait_step(wait_step);

            // 进入下半个周期并等待对方读写
            mcu_io_set_state(clk_pin, !clk_init_state);
            mcu_timer_wait_step(wait_step);
            
            // 周期快要结束时读取
            if (rx && mcu_io_get_state(miso_pin))
            {
                rx[i] |= mask[j];
            }

            mcu_io_set_state(clk_pin, clk_init_state);
        }
    }

    // 取消片选
    mcu_io_set_state(spi->m_cs_pin, true);
}

 

posted on 2024-09-03 02:13  kehuadong  阅读(27)  评论(0)    收藏  举报

导航