SPI

Overview

以 AC638N 为例,配置两个spi的样机自发自收环回测试。spi1设置为主机模式,spi2设置为从机模式,spi1发送数据到spi2,然后spi1接收spi2原样返回的数据,然后比较发送出去的数据与接收的数据是否一致,一致则说明验证通过。提供 SPI 的应用示例、工程配置、API 介绍和常见问题。

应用示例

  • SPI 的具体源代码详见 sdk/bsp/AC638N/src/spi.c

  • spi.c 中参考示例如下:

    void spi_test_main()
    {
        int i;
        int err;
    
        spi_open(spi1_hdl);
        spi_open(spi2_hdl);
        spi_set_ie(spi2_hdl, 1);
        request_irq(IRQ_SPI2_IDX, 3, spi2_isr, 0);//配置中断优先级,中断函数
    //spi cs init
        spi_cs_init(IO_PORTB_04, 0); //spi1 cs out
        spi_cs_init(IO_PORTA_03, 1); //spi2 cs in
        for (i = 0; i < 100; i++) {
            spi1_send_buf[i] = i % 26 + 'A';
            spi1_recv_buf[i] = 0;
        }
        log_info(">>> spi test start");
    #if SPI_TEST_BYTE_MODE_EN
        log_info(">>> spi byte test");
        gpio_write(IO_PORTB_04, 0);
        for (i = 0; i < 100; i++) {
            err = spi_send_byte(spi1_hdl, spi1_send_buf[i]);
            if (err) {
                log_info("spi1 byte send timeout");
                break;
            }
            delay(100);
            spi1_recv_buf[i] = spi_recv_byte(spi1_hdl, &err);
            if (err) {
                log_info("spi1 byte recv timeout");
                break;
            }
            delay(100);
        }
        gpio_write(IO_PORTB_04, 1);
    #else
        log_info(">>> spi dma test");
        spi_dma_set_addr_for_isr(spi2_hdl, spi2_recv_buf, 100, 1);
        gpio_write(IO_PORTB_04, 0);
        err = spi_dma_send(spi1_hdl, spi1_send_buf, 100);
        if (err < 0) {
            log_info("spi1 dma send timeout");
            goto __out_dma;
        }
    
        err = spi_dma_recv(spi1_hdl, spi1_recv_buf, 100);//delay(100);
        if (err < 0) {
            log_info("spi1 dma recv timeout");
            goto __out_dma;
        }
    
    __out_dma://delay(100);
        gpio_write(IO_PORTB_04, 1);
    #endif
        log_info("<<< spi test end");
    
        log_info("\nspi master receivce buffer:\n");
        put_buf(spi1_recv_buf, 100);
    
        if (!memcmp(spi1_send_buf, spi1_recv_buf, 100)) {
            log_info("\nspi test pass\n");
        } else {
            log_info("\nspi test fail\n");
        }
    
        spi_close(spi1_hdl);
        spi_close(spi2_hdl);
    }
    

工程配置

  • sdk/bsp/AC638N/board/board_demo.c 中配置SPI:

    /*********** SPI config ***********/
    #if TCFG_HW_SPI1_ENABLE
    const struct spi_platform_data spi1_p_data = {
        .port = {
            IO_PORTB_06,    //CLK
            IO_PORTB_07,    //DO
            IO_PORTB_08,    //DI
        },
        .mode = SPI_MODE_BIDIR_1BIT,
        .clk = 1000000,
        .role = SPI_ROLE_MASTER,
    };
    #endif
    #if TCFG_HW_SPI2_ENABLE
    const struct spi_platform_data spi2_p_data = {
        .port = {
            IO_PORTB_01,    //CLK
            IO_PORTB_02,    //DO
            IO_PORTB_03,    //DI
        },
        .mode = SPI_MODE_BIDIR_1BIT,
        .clk = 1000000,
        .role = SPI_ROLE_SLAVE,
    };
    #endif
    
  • sdk/apps/main.c 中函数 user_main() 添加如下工程代码:

    int user_main()
    {
        extern void spi_test_main(void);
        spi_test_main();
    }
    
  • 编译下载后,PB4接PA3,PB1接PB6,PB2接PB8,PB3接PB7。复位后若打印 “spi test pass” ,则表示spi1主机发送的数据和接收的数据一致。

API参考

SPI 常用相关 API 介绍,具体软件代码见 sdk/bsp/AC638N/src/spi.c

Functions

int spi_open(spi_dev spi)

打开spi

Parameters:

spi – spi句柄

Returns:

0 成功,< 0 失败

int spi_dma_recv(spi_dev spi, void *buf, u32 len)

spi dma接收

Parameters:
  • spi – spi句柄

  • buf – 接收缓冲区基地址

  • len – 期望接收长度

Returns:

实际接收长度,< 0表示失败

int spi_dma_send(spi_dev spi, const void *buf, u32 len)

spi dma发送

Parameters:
  • spi – spi句柄

  • buf – 发送缓冲区基地址

  • len – 期望发送长度

Returns:

实际发送长度,< 0表示失败

void spi_dma_set_addr_for_isr(spi_dev spi, void *buf, u32 len, u8 rw)

spi 配置dma,不等待pnd,用于中断

Parameters:
  • spi – spi句柄

  • buf – 缓冲区基地址

  • len – 期望长度

  • rw – 1 接收 / 0 发送

Returns:

null

void spi_set_ie(spi_dev spi, u8 en)

中断使能

Parameters:
  • spi – spi句柄

  • en – 1 使能,0 失能

Returns:

null

u8 spi_get_pending(spi_dev spi)

判断中断标志

Parameters:

spi – spi句柄

Returns:

0 无png / 1 有png

void spi_clear_pending(spi_dev spi)

清除中断标志

Parameters:

spi – spi句柄

Returns:

null

void spi_set_bit_mode(spi_dev spi, int mode)

设置spi[单向/双向,位数]模式

Parameters:
  • spi – spi句柄

  • mode – 模式: SPI_MODE_BIDIR_1BIT, //支持SPIx(x=0,1,2),全双工,di接收,do发送 SPI_MODE_UNIDIR_1BIT, //支持SPIx(x=0,1,2),半双工,do分时发送/接收 SPI_MODE_UNIDIR_2BIT, //支持SPIx(x=0),半双工,di & do共2bit分时发送/接收 SPI_MODE_UNIDIR_4BIT, //支持SPIx(x=0),半双工,di & do共4bit分时发送/接收

Returns:

null

u8 spi_recv_byte(spi_dev spi, int *err)

接收1个字节

Parameters:
  • spi – spi句柄

  • err – 返回错误信息,若err为非空指针,0 成功,< 0 失败,若为空指针,忽略

Returns:

接收的字节

u8 spi_recv_byte_for_isr(spi_dev spi)

接收1个字节,不等待pnd,用于中断

Parameters:

spi – spi句柄

Returns:

接收的字节

int spi_send_byte(spi_dev spi, u8 byte)

发送1个字节

Parameters:
  • spi – spi句柄

  • byte – 发送的字节

Returns:

0 成功,< 0 失败

void spi_send_byte_for_isr(spi_dev spi, u8 byte)

发送1个字节,不等待pnd,用于中断

Parameters:
  • spi – spi句柄

  • byte – 发送的字节

Returns:

null

u8 spi_send_recv_byte(spi_dev spi, u8 byte, int *err)

发送并接收1个字节,在8个时钟内完成,仅使用于SPI_MODE_BIDIR_1BIT

Parameters:
  • spi – spi句柄

  • byte – 发送的字节

  • err – 返回错误信息,若err为非空指针,0 成功,< 0 失败,若为空指针,忽略

Returns:

接收的字节

int spi_set_baud(spi_dev spi, u32 baud)

设置波特率

Parameters:
  • spi – spi句柄

  • baud – 波特率

Returns:

0 成功,< 0 失败

u32 spi_get_baud(spi_dev spi)

获取波特率

Parameters:

spi – spi句柄

Returns:

波特率

void spi_close(spi_dev spi)

关闭spi

Parameters:

spi – spi句柄

Returns:

null