BES2300YP - SPI接口

本文详细讲述了在2300YP平台中如何通过GPIOPinMux进行SPI和SPILCD功能的正确配置,包括PinMux代码解析、功能映射的调整以及hal_iomux_set_spilcd的使用。特别强调了在实际应用中遇到的GPIO复用问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

GPIO Pin Mux

Pin Mux相关的代码

Hal_spi.c/h的几组api

hal_iomux_set_spilcd

我的测试代码


GPIO Pin Mux

SPI的调试需要考虑GPIO的选择和复用设定, 

最开始的时候我拿到的是GPIO Pin Mux的Excel, 整理如下:

后面的研究发现这里有坑

Pin Mux相关的代码

hal_iomux_best2300p.c文件中pin_func_map函数定义了每个引脚所支持的各种复用功能,

我们可以注意到上节所说的坑, 因为这里的定义和上节的excel是对应不上的, 解决方法:应该采用SPILCD而不是SPI的相关接口.

至于SPI接口, 因为我的2300YP没有P04~07,所以用不上, 如果换成其他芯片和封装, 可以具体再研究下

其定义如下:

// 为方便阅读, 和针对2300yp, 部分无效引脚的代码删除

static const enum HAL_IOMUX_FUNCTION_T pin_func_map[HAL_IOMUX_PIN_NUM][IOMUX_ALT_FUNC_NUM] = {
    // P0_0
    { HAL_IOMUX_FUNC_I2S0_SDI0, HAL_IOMUX_FUNC_UART2_RX, HAL_IOMUX_FUNC_PCM_DI, HAL_IOMUX_FUNC_SPILCD_DI0,
      HAL_IOMUX_FUNC_PDM0_CK, HAL_IOMUX_FUNC_SPILCD_DCN, },
    // P0_1
    { HAL_IOMUX_FUNC_I2S0_SDO, HAL_IOMUX_FUNC_UART2_TX, HAL_IOMUX_FUNC_PCM_DO, HAL_IOMUX_FUNC_SPILCD_DIO,
      HAL_IOMUX_FUNC_PDM0_D, HAL_IOMUX_FUNC_NONE, },
    // P0_2
    { HAL_IOMUX_FUNC_I2S0_WS, HAL_IOMUX_FUNC_I2C_M1_SCL, HAL_IOMUX_FUNC_PCM_FSYNC, HAL_IOMUX_FUNC_SPILCD_CS0,
      HAL_IOMUX_FUNC_PDM1_D, HAL_IOMUX_FUNC_NONE, },
    // P0_3
    { HAL_IOMUX_FUNC_I2S0_SCK, HAL_IOMUX_FUNC_I2C_M1_SDA, HAL_IOMUX_FUNC_PCM_CLK, HAL_IOMUX_FUNC_SPILCD_CLK,
      HAL_IOMUX_FUNC_PDM2_D, HAL_IOMUX_FUNC_NONE, },
   


    // P1_0
    { HAL_IOMUX_FUNC_SDMMC_DATA2, HAL_IOMUX_FUNC_I2S1_SCK, HAL_IOMUX_FUNC_SPILCD_CLK, HAL_IOMUX_FUNC_SPI_CS1,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P1_1
    { HAL_IOMUX_FUNC_SDMMC_DATA3, HAL_IOMUX_FUNC_I2S1_WS, HAL_IOMUX_FUNC_SPILCD_CS0, HAL_IOMUX_FUNC_SPI_CS2,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P1_2
    { HAL_IOMUX_FUNC_SDMMC_CMD, HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_SPILCD_CS1, HAL_IOMUX_FUNC_SPI_CS3,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P1_3
    { HAL_IOMUX_FUNC_SDMMC_CLK, HAL_IOMUX_FUNC_I2S0_MCLK, HAL_IOMUX_FUNC_SPILCD_DCN, HAL_IOMUX_FUNC_CLK_OUT,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P1_4
    { HAL_IOMUX_FUNC_SDMMC_DATA0, HAL_IOMUX_FUNC_I2S1_SDI0, HAL_IOMUX_FUNC_SPILCD_DI0, HAL_IOMUX_FUNC_NONE,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P1_5
    { HAL_IOMUX_FUNC_SDMMC_DATA1, HAL_IOMUX_FUNC_I2S1_SDO, HAL_IOMUX_FUNC_SPILCD_DIO, HAL_IOMUX_FUNC_I2S0_MCLK,
      HAL_IOMUX_FUNC_CLK_OUT, HAL_IOMUX_FUNC_NONE, },


    // P1_6
    { HAL_IOMUX_FUNC_UART0_RX, HAL_IOMUX_FUNC_I2C_M0_SCL, HAL_IOMUX_FUNC_BT_UART_RX, HAL_IOMUX_FUNC_NONE,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P1_7
    { HAL_IOMUX_FUNC_UART0_TX, HAL_IOMUX_FUNC_I2C_M0_SDA, HAL_IOMUX_FUNC_BT_UART_TX, HAL_IOMUX_FUNC_NONE,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },

    // P2_2
    { HAL_IOMUX_FUNC_I2C_M1_SCL, HAL_IOMUX_FUNC_UART2_RX, HAL_IOMUX_FUNC_UART1_CTS, HAL_IOMUX_FUNC_BT_UART_CTS,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_I2S0_MCLK, },
    // P2_3
    { HAL_IOMUX_FUNC_I2C_M1_SDA, HAL_IOMUX_FUNC_UART2_TX, HAL_IOMUX_FUNC_UART1_RTS, HAL_IOMUX_FUNC_BT_UART_RTS,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_CLK_OUT, },


    // P2_5
    { HAL_IOMUX_FUNC_PWM1, HAL_IOMUX_FUNC_CLK_REQ_IN, HAL_IOMUX_FUNC_SPI_CS3, HAL_IOMUX_FUNC_NONE,
      HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_NONE, },
    // P2_6
    { HAL_IOMUX_FUNC_PWM2, HAL_IOMUX_FUNC_SPILCD_DI1, HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_SPDIF0_DI,
      HAL_IOMUX_FUNC_CLK_32K_IN, HAL_IOMUX_FUNC_NONE, },
    // P2_7
    { HAL_IOMUX_FUNC_PWM3, HAL_IOMUX_FUNC_SPILCD_CS1, HAL_IOMUX_FUNC_NONE, HAL_IOMUX_FUNC_SPDIF0_DO,
      HAL_IOMUX_FUNC_CLK_OUT, HAL_IOMUX_FUNC_NONE, },
};

在hal_iomux_set_function函数中会基于pin_func_map来将功能序号转为寄存器掩码值,

这段代码如下:

// Other func values: 0 -> gpio, 6 -> rf_ana, 7 -> jtag/btdm, 9 -> clk_req, 10 -> ana_test
static const uint8_t index_to_func_val[IOMUX_ALT_FUNC_NUM] = { 1, 2, 3, 4, 5, 8, };

if (func == HAL_IOMUX_FUNC_GPIO) {
    val = IOMUX_FUNC_VAL_GPIO;
}
else
{
    for (i = 0; i < IOMUX_ALT_FUNC_NUM; i++)
    {
        if (pin_func_map[pin][i] == func)
        {
            break;
        }
    }

    if (i == IOMUX_ALT_FUNC_NUM) {
        return 3;
    }
    val = index_to_func_val[i];
}

reg = &iomux->REG_004 + pin / 8;
shift = (pin % 8) * 4;

*reg = (*reg & ~(0xF << shift)) | (val << shift);

Hal_spi.c/h的几组api

Hal_spi.c/h中有几组不同的api, 每组api有不同的原语(这个词我可能用的不合适)实现, 总结如下:

粗略的喵了一下, 这几组api只是用不同SPI_id调用一组后缀带_id的函数

所以这里我们应该可以忽略spi和spilcd的差别, 使用spilcd来替代本来预期的spi模块

hal_iomux_set_spilcd

这两个函数在hal_iomux_best2300p.c中定义, 是用来将GPIO的功能设定为用于SPILCD的.

他依赖于宏来控制所用的引脚, 以及SPI接口类型(3线或4线)

我的宏定义如下

#define SPILCD_IOMUX_4WIRE

// 使用GPIO 00~03时
#define SPILCD_IOMUX_DI0_INDEX 0

// 使用GPIO 10,11,14,15时
#define SPILCD_IOMUX_INDEX 10
#define SPILCD_IOMUX_DI0_INDEX 14

如果实在不放心, 请用以下函数

#define USE_GPIO_0_FOR_SPI

void my_iomux_set_spi()
{
    #ifdef USE_GPIO_0_FOR_SPI
    static const struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux_spi_4wire[4] = {
        {HAL_IOMUX_PIN_P0_3, HAL_IOMUX_FUNC_SPILCD_CLK, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
        {HAL_IOMUX_PIN_P0_2, HAL_IOMUX_FUNC_SPILCD_CS0,  HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
        {HAL_IOMUX_PIN_P0_1, HAL_IOMUX_FUNC_SPILCD_DIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
        {HAL_IOMUX_PIN_P0_0, HAL_IOMUX_FUNC_SPILCD_DI0, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
    };
    #else // USE_GPIO_0_FOR_SPI
    static const struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux_spi_4wire[4] = {
        {HAL_IOMUX_PIN_P1_0, HAL_IOMUX_FUNC_SPILCD_CLK, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
        {HAL_IOMUX_PIN_P1_1, HAL_IOMUX_FUNC_SPILCD_CS0,  HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
        {HAL_IOMUX_PIN_P1_5, HAL_IOMUX_FUNC_SPILCD_DIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
        {HAL_IOMUX_PIN_P1_4, HAL_IOMUX_FUNC_SPILCD_DI0, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
    };
    #endif //USE_GPIO_0_FOR_SPI

    hal_iomux_init(pinmux_spi_4wire, ARRAY_SIZE(pinmux_spi_4wire));
}

我的测试代码


#include "hal_spi.h"

#define SPI_DMA_SEND  hal_spilcd_dma_send
#define SPI_DMA_RECV  hal_spilcd_dma_recv
#define SPI_ENABLE_AND_SEND  hal_spilcd_enable_and_send
#define SPI_ENABLE_AND_RECV  hal_spilcd_enable_and_recv
#define SPI_OPEN  hal_spilcd_open
extern void hal_iomux_set_spilcd(void);
#define IOMUX_SET_SPI hal_iomux_set_spilcd

static const struct HAL_SPI_CFG_T _spi_cfg_default =
{
    .rate = 200000,
    .clk_delay_half = true,
    .clk_polarity = true,
    .slave = false,
    .dma_rx = true,
    .dma_tx = true,
    .rx_sep_line = true,
    .cs = 0,
    .tx_bits = 32,
    .rx_bits = 32,
    .rx_frame_bits = 0,
};

static struct HAL_SPI_CTRL_T _spi_ctrl_8bit;

void spi_test()
{
    TRACE(1,"spi_test start!");
    IOMUX_SET_SPI();
    // my_iomux_set_spi();
    int32_t ret = SPI_OPEN(&_spi_cfg_default);
    TRACE(3,"%s, spi open failed! ret = %d", __func__, ret);

    while(1)
    {
        uint8_t cmd[4];    
        cmd[0] = 0XAA;
        cmd[1] = 0X55;
        cmd[2] = 0XAA;
        cmd[3] = 0X55;

        ret = SPI_ENABLE_AND_SEND(&_spi_ctrl_8bit, cmd, sizeof(cmd));
        TRACE(3,"%s, spi 1 send, ret = %d", __func__, ret);
        osDelay(10);

        ret = SPI_DMA_SEND(cmd, sizeof(cmd), NULL);
        TRACE(3,"%s, spi dma send, ret = %d", __func__, ret);
        osDelay(10);
    }

    TRACE(1,"spi_test done !");
}

// 测试时, 在app_init之前调用了spi_test

欢迎阅读更多 BES专栏文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值