1670|4

26

帖子

2

TA的资源

一粒金砂(中级)

楼主
 

小熊派BearPi-Pico H2821星闪开发板测评(四)——多种有线数据传输测试 [复制链接]

UART

UART为通用异步收发器,在实际接线中,一个设备的RX引脚接到另一个设备的TX引脚,除此之外,还需要定义串口号,波特率,数据位,起始位,停止位,以及数据传输的大小等。

小熊派上的UART代码实现:

#include "pinctrl.h"
#include "uart.h"
#include "watchdog.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define UART_BAUDRATE                      115200
#define UART_DATA_BITS                     3
#define UART_STOP_BITS                     1
#define UART_PARITY_BIT                    0
#define UART_TRANSFER_SIZE                 512
#define CONFIG_UART_INT_WAIT_MS            5

#define UART_TASK_STACK_SIZE               0x1000
#define UART_TASK_DURATION_MS              500
#define UART_TASK_PRIO                     (osPriority_t)(17)

static uint8_t g_app_uart_rx_buff[UART_TRANSFER_SIZE] = { 0 };
#if defined(CONFIG_UART_INT_TRANSFER_MODE)
static uint8_t g_app_uart_int_rx_flag = 0;
#endif
static uart_buffer_config_t g_app_uart_buffer_config = {
    .rx_buffer = g_app_uart_rx_buff,
    .rx_buffer_size = UART_TRANSFER_SIZE
};


static void app_uart_init_pin(void)
{
    if (CONFIG_UART_BUS_ID == 0) {
        uapi_pin_set_mode(CONFIG_UART_TXD_PIN, HAL_PIO_UART_L0_TXD);
        uapi_pin_set_mode(CONFIG_UART_RXD_PIN, HAL_PIO_UART_L0_RXD);       
    }else if (CONFIG_UART_BUS_ID == 1) {
        uapi_pin_set_mode(CONFIG_UART_TXD_PIN, HAL_PIO_UART_H0_TXD);
        uapi_pin_set_mode(CONFIG_UART_RXD_PIN, HAL_PIO_UART_H0_RXD);       
    }else if (CONFIG_UART_BUS_ID == 2) {
        uapi_pin_set_mode(CONFIG_UART_TXD_PIN, HAL_PIO_UART_L1_TXD);
        uapi_pin_set_mode(CONFIG_UART_RXD_PIN, HAL_PIO_UART_L1_RXD);       
    }
}

static void app_uart_init_config(void)
{
    uart_attr_t attr = {
        .baud_rate = UART_BAUDRATE,
        .data_bits = UART_DATA_BITS,
        .stop_bits = UART_STOP_BITS,
        .parity = UART_PARITY_BIT
    };

    uart_pin_config_t pin_config = {
        .tx_pin = CONFIG_UART_TXD_PIN,
        .rx_pin = CONFIG_UART_RXD_PIN,
        .cts_pin = PIN_NONE,
        .rts_pin = PIN_NONE
    };
    uapi_uart_deinit(CONFIG_UART_BUS_ID);
    uapi_uart_init(CONFIG_UART_BUS_ID, &pin_config, &attr, NULL, &g_app_uart_buffer_config);

}

#if defined(CONFIG_UART_INT_TRANSFER_MODE)
static void app_uart_read_int_handler(const void *buffer, uint16_t length, bool error)
{
    unused(error);
    if (buffer == NULL || length == 0) {
        osal_printk("uart%d int mode transfer illegal data!\r\n", CONFIG_UART_BUS_ID);
        return;
    }
    uint8_t *buff = (uint8_t *)buffer;
    if (memcpy_s(g_app_uart_rx_buff, length, buff, length) != EOK) {
        osal_printk("uart%d int mode data copy fail!\r\n", CONFIG_UART_BUS_ID);
        return;
    }
    g_app_uart_int_rx_flag = 1;
}

static void app_uart_write_int_handler(const void *buffer, uint32_t length, const void *params)
{
    unused(params);
    uint8_t *buff = (void *)buffer;
    for (uint32_t i = 0; i < length; i++) {
        osal_printk("uart%d write data[%d] = %d\r\n", CONFIG_UART_BUS_ID, i, buff[i]);
    }
    
}
#endif

static void *uart_task(const char *arg)
{
    unused(arg);
    /* UART pinmux. */
    app_uart_init_pin();

    /* UART init config. */
    app_uart_init_config();

#if defined(CONFIG_UART_INT_TRANSFER_MODE)
    osal_printk("uart%d int mode register receive callback start!\r\n", CONFIG_UART_BUS_ID);
    uapi_uart_unregister_rx_callback(CONFIG_UART_BUS_ID);
    if (uapi_uart_register_rx_callback(CONFIG_UART_BUS_ID, UART_RX_CONDITION_FULL_OR_IDLE,
                                       1, app_uart_read_int_handler) == ERRCODE_SUCC) {
        osal_printk("uart%d int mode register receive callback succ!\r\n", CONFIG_UART_BUS_ID);
    }
#endif

    while (1) {
        osDelay(UART_TASK_DURATION_MS);
#if defined(CONFIG_UART_POLL_TRANSFER_MODE)
        osal_printk("uart%d poll mode receive start!\r\n", CONFIG_UART_BUS_ID);
        (void)uapi_watchdog_kick();
        if (uapi_uart_read(CONFIG_UART_BUS_ID, g_app_uart_rx_buff, UART_TRANSFER_SIZE, 0) == UART_TRANSFER_SIZE) {
            osal_printk("uart%d poll mode receive succ!\r\n", CONFIG_UART_BUS_ID);
        }
        osal_printk("uart%d poll mode send back!\r\n", CONFIG_UART_BUS_ID);
        if (uapi_uart_write(CONFIG_UART_BUS_ID, g_app_uart_rx_buff, UART_TRANSFER_SIZE, 0) == UART_TRANSFER_SIZE) {
            osal_printk("uart%d poll mode send back succ!\r\n", CONFIG_UART_BUS_ID);
        }
#endif
#if defined(CONFIG_UART_INT_TRANSFER_MODE)
        while (g_app_uart_int_rx_flag != 1) {
            osDelay(CONFIG_UART_INT_WAIT_MS);
        }
        g_app_uart_int_rx_flag = 0;
        osal_printk("uart%d int mode send back!\r\n", CONFIG_UART_BUS_ID);
        if (uapi_uart_write_int(CONFIG_UART_BUS_ID, g_app_uart_rx_buff, UART_TRANSFER_SIZE, 0,
                                app_uart_write_int_handler) == ERRCODE_SUCC) {
            osal_printk("uart%d int mode send back succ!\r\n", CONFIG_UART_BUS_ID);
        }
#endif
    }

    return NULL;
}

static void uart_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "UartTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = UART_TASK_STACK_SIZE;
    attr.priority = UART_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)uart_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the uart_entry. */
app_run(uart_entry);

选择数据互传模式(CONFIG_UART_INT_TRANSFER_MODE),并用USB转TTL工具将开发板上定义的RX,TX引脚与PC相连,输入字符串,开发板会回复相应的ASCII码值。

 

需要特别注意的是:

  1. H2821虽然有三个UART,但是UART0用于烧录和日志打印;UART1用于协议栈的日志打印,需要配套特殊工具才能看到;只有UART2是闲置的,因此在串口调试时,除去日志打印,最好使用UART2
  2. 在设置数据位长度时,代码为" #define UART_DATA_BITS 3 ",在H2821的定义中,3位数据位即为8位数据位,同理,0-3位数据位即为5-8位数据位

I2C主从数据传输测试

I2C使用两根信号线进行通信:一根时钟线SCL,一根数据线SDA。IIC将SCL处于高时SDA拉低的动作作为开始信号,SCL处于高时SDA拉高的动作作为结束信号;传输数据时,SDA在SCL低电平时改变数据,在SCL高电平时保持数据,每个SCL脉冲的高电平传递1位数据。

小熊派上I2C代码实现:

对于主设备,需要定义SCL/SDA引脚、波特率、传输量以及主从设备地址:

#include "pinctrl.h"
#include "i2c.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define I2C_MASTER_ADDR                   0x0
#define I2C_SLAVE_ADDR                    0x8
#define I2C_SET_BAUDRATE                  500000


#define I2C_TASK_STACK_SIZE               0x1000
#define I2C_TASK_DURATION_MS              500
#define I2C_TASK_PRIO                     (osPriority_t)(17)

static void app_i2c_init_pin(void)
{
    /* I2C pinmux. */
    if (CONFIG_I2C_MASTER_BUS_ID == 0) {
        uapi_pin_set_mode(CONFIG_I2C_SCL_MASTER_PIN, HAL_PIO_I2C0_CLK);
        uapi_pin_set_mode(CONFIG_I2C_SDA_MASTER_PIN, HAL_PIO_I2C0_DATA);       
    }else if (CONFIG_I2C_MASTER_BUS_ID == 1) {
        uapi_pin_set_mode(CONFIG_I2C_SCL_MASTER_PIN, HAL_PIO_I2C1_CLK);
        uapi_pin_set_mode(CONFIG_I2C_SDA_MASTER_PIN, HAL_PIO_I2C1_DATA);       
    }
    uapi_pin_set_pull(CONFIG_I2C_SCL_MASTER_PIN, PIN_PULL_UP);
    uapi_pin_set_pull(CONFIG_I2C_SDA_MASTER_PIN, PIN_PULL_UP);
}

static void *i2c_master_task(const char *arg)
{
    unused(arg);
    i2c_data_t data = { 0 };

    uint32_t baudrate = I2C_SET_BAUDRATE;
    uint8_t hscode = I2C_MASTER_ADDR;
    uint16_t dev_addr = I2C_SLAVE_ADDR;

    /* I2C master init config. */

    app_i2c_init_pin();
    uapi_i2c_master_init(CONFIG_I2C_MASTER_BUS_ID, baudrate, hscode);

    /* I2C data config. */
    uint8_t tx_buff[CONFIG_I2C_TRANSFER_LEN] = { 0 };
    for (uint32_t loop = 0; loop < CONFIG_I2C_TRANSFER_LEN; loop++) {
        tx_buff[loop] = (loop & 0xFF);
    }

    uint8_t rx_buff[CONFIG_I2C_TRANSFER_LEN] = { 0 };
    data.send_buf = tx_buff;
    data.send_len = CONFIG_I2C_TRANSFER_LEN;
    data.receive_buf = rx_buff;
    data.receive_len = CONFIG_I2C_TRANSFER_LEN;

    while (1) {
        osDelay(I2C_TASK_DURATION_MS);
        osal_printk("i2c%d master send start!\r\n", CONFIG_I2C_MASTER_BUS_ID);
        if (uapi_i2c_master_write(CONFIG_I2C_MASTER_BUS_ID, dev_addr, &data) == ERRCODE_SUCC) {
            osal_printk("i2c%d master send succ!\r\n", CONFIG_I2C_MASTER_BUS_ID);
        } else {
            continue;
        }
        osal_printk("i2c%d master receive start!\r\n", CONFIG_I2C_MASTER_BUS_ID);
        if (uapi_i2c_master_read(CONFIG_I2C_MASTER_BUS_ID, dev_addr, &data) == ERRCODE_SUCC) {
            for (uint32_t i = 0; i < data.receive_len; i++) {
                osal_printk("i2c%d master receive data is %x\r\n", CONFIG_I2C_MASTER_BUS_ID, data.receive_buf[i]);
            }
            osal_printk("i2c%d master receive succ!\r\n", CONFIG_I2C_MASTER_BUS_ID);
        }
    }

    return NULL;
}

static void i2c_master_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "I2cMasterTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = I2C_TASK_STACK_SIZE;
    attr.priority = I2C_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)i2c_master_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the i2c_master_entry. */
app_run(i2c_master_entry);

对于从设备,只需定义SCL/SDA引脚和从设备地址即可:

#include "pinctrl.h"
#include "i2c.h"
#include "errcode.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define I2C_SLAVE_ADDR                    0x8
#define I2C_SET_BAUDRATE                  500000

#define I2C_TASK_STACK_SIZE               0x1000
#define I2C_TASK_DURATION_MS              100
#define I2C_TASK_PRIO                     (osPriority_t)(17)

static void app_i2c_init_pin(void)
{
    /* I2C pinmux. */
    if (CONFIG_I2C_SLAVE_BUS_ID == 0) {
        uapi_pin_set_mode(CONFIG_I2C_SCL_SLAVE_PIN, HAL_PIO_I2C0_CLK);
        uapi_pin_set_mode(CONFIG_I2C_SDA_SLAVE_PIN, HAL_PIO_I2C0_DATA);       
    }else if (CONFIG_I2C_SLAVE_BUS_ID == 1) {
        uapi_pin_set_mode(CONFIG_I2C_SCL_SLAVE_PIN, HAL_PIO_I2C1_CLK);
        uapi_pin_set_mode(CONFIG_I2C_SDA_SLAVE_PIN, HAL_PIO_I2C1_DATA);       
    }
    uapi_pin_set_pull(CONFIG_I2C_SCL_SLAVE_PIN, PIN_PULL_UP);
    uapi_pin_set_pull(CONFIG_I2C_SDA_SLAVE_PIN, PIN_PULL_UP);
}

void *i2c_slave_task(const char *arg)
{
    unused(arg);
    i2c_data_t data = { 0 };

    uint32_t baudrate = I2C_SET_BAUDRATE;
    uint16_t dev_addr = I2C_SLAVE_ADDR;

    /* I2C slave init config. */
    app_i2c_init_pin();
    uapi_i2c_slave_init(CONFIG_I2C_SLAVE_BUS_ID, baudrate, dev_addr);

    /* I2C data config. */
    uint8_t tx_buff[CONFIG_I2C_TRANSFER_LEN] = { 0 };
    for (uint32_t loop = 0; loop < CONFIG_I2C_TRANSFER_LEN; loop++) {
        tx_buff[loop] = (loop & 0xFF);
    }

    uint8_t rx_buff[CONFIG_I2C_TRANSFER_LEN] = { 0 };
    data.send_buf = tx_buff;
    data.send_len = CONFIG_I2C_TRANSFER_LEN;
    data.receive_buf = rx_buff;
    data.receive_len = CONFIG_I2C_TRANSFER_LEN;

    while (1) {
        osDelay(I2C_TASK_DURATION_MS);
        osal_printk("i2c%d slave receive start!\r\n", CONFIG_I2C_SLAVE_BUS_ID);
        if (uapi_i2c_slave_read(CONFIG_I2C_SLAVE_BUS_ID, &data) == ERRCODE_SUCC) {
            for (uint32_t i = 0; i < data.receive_len; i++) {
                osal_printk("i2c slave receive data is %x\r\n", data.receive_buf[i]);
            }
            osal_printk("i2c%d slave receive succ!\r\n", CONFIG_I2C_SLAVE_BUS_ID);
        }
        osal_printk("i2c%d slave send start!\r\n", CONFIG_I2C_SLAVE_BUS_ID);
        if (uapi_i2c_slave_write(CONFIG_I2C_SLAVE_BUS_ID, &data) == ERRCODE_SUCC) {
            osal_printk("i2c%d slave send succ!\r\n", CONFIG_I2C_SLAVE_BUS_ID);
        }
    }

    return NULL;
}

static void i2c_slave_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "I2cSlaveTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = I2C_TASK_STACK_SIZE;
    attr.priority = I2C_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)i2c_slave_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the i2c_slave_entry. */
app_run(i2c_slave_entry);

取两块核心板,将二者的SCL引脚相连、二者SDA引脚相连、二者GND相连,主设备发送数据,从设备接收数据,在串口工具中观察二者的收发日志信息。

输出结果如下:

 

I2S主从数据传输测试

I2S主要应用于数字音频接口,用到的信号线包括时钟线、左/右声道线以及数据线。对于H2821,需要定义的引脚包括时钟引脚(CLK),通道选择引脚(WS),数据输出引脚(DO),数据输入引脚(DI)。这里的DO和DI我认为应该就是左右声道。

代码实现:

对于主设备,需要定义引脚、位宽、通道数、传输时间和数据量

#include "common_def.h"
#include "pinctrl.h"
#include "i2s.h"
#include "tcxo.h"
#include "hal_sio.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define I2S_DATA_WIDTH             24
#define I2S_NUMBER_OF_CHANNELS     2
#define TCXO_DELAY_MS              1000

#define I2S_TASK_STACK_SIZE        0x1000
#define I2S_TASK_DURATION_MS       500
#define I2S_TASK_PRIO              (osPriority_t)(17)

static uint32_t g_app_left_data[CONFIG_I2S_TRANSFER_LEN];
static uint32_t g_app_right_data[CONFIG_I2S_TRANSFER_LEN];
static i2s_tx_data_t g_app_write_data = {
    .left_buff = g_app_left_data,
    .right_buff = g_app_right_data,
    .length = CONFIG_I2S_TRANSFER_LEN,
};

static void app_i2s_init_pin(void)
{
    /* I2S pinmux. */
    uapi_pin_set_mode(CONFIG_I2S_CLK_MASTER_PIN, HAL_PIO_I2S_SCLK);
    uapi_pin_set_mode(CONFIG_I2S_WS_MASTER_PIN, HAL_PIO_I2S_WS);
    uapi_pin_set_mode(CONFIG_I2S_DO_MASTER_PIN, HAL_PIO_I2S_DOUT);
    uapi_pin_set_mode(CONFIG_I2S_DI_MASTER_PIN, HAL_PIO_I2S_DIN);
}

void app_i2s_rx_callbcak(uint32_t *left_buff, uint32_t *right_buff, uint32_t length)
{
    for (uint32_t i = 0; i < length; i++) {
        osal_printk("left rx data is:0x%0x\r\n", left_buff[i]);
        osal_printk("right rx data is:0x%0x\r\n", right_buff[i]);
    }
}

static void *i2s_master_task(const char *arg)
{
    unused(arg);
    i2s_config_t config = {
        .drive_mode= MASTER,
        .transfer_mode = STD_MODE,
        .data_width = TWENTY_FOUR_BIT,
        .channels_num = TWO_CH,
        .timing = NONE_MODE,
        .clk_edge = NONE_EDGE,
        .div_number = I2S_DATA_WIDTH,
        .number_of_channels = I2S_NUMBER_OF_CHANNELS,
    };
    uint32_t i2s_first_data = 0x100000;
    for (uint32_t i = 0; i < CONFIG_I2S_TRANSFER_LEN; i++) {
        g_app_left_data[i] = i2s_first_data;
        g_app_right_data[i] = i2s_first_data;
        i2s_first_data++;
    }
    app_i2s_init_pin();
    /* I2S init. */
    uapi_i2s_init(CONFIG_I2S_MASTER_BUS_ID, app_i2s_rx_callbcak);
    uapi_i2s_set_config(CONFIG_I2S_MASTER_BUS_ID, &config);

    while (1) {
        osDelay(I2S_TASK_DURATION_MS);
        osal_printk("i2s master write start!\r\n");
        uapi_i2s_write_data(CONFIG_I2S_MASTER_BUS_ID, &g_app_write_data);
        uapi_tcxo_delay_ms(TCXO_DELAY_MS);
    }

    return NULL;
}

static void i2s_master_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "I2sMasterTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = I2S_TASK_STACK_SIZE;
    attr.priority = I2S_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)i2s_master_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the i2s_master_entry. */
app_run(i2s_master_entry);

对于从设备,需要定义引脚、位宽和通道数:

#include "common_def.h"
#include "pinctrl.h"
#include "i2s.h"
#include "hal_sio.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define I2S_DATA_WIDTH             24
#define I2S_NUMBER_OF_CHANNELS     2

#define I2S_TASK_STACK_SIZE        0x1000
#define I2S_TASK_PRIO              (osPriority_t)(17)

static void app_i2s_init_pin(void)
{
    /* I2S pinmux. */
    uapi_pin_set_mode(CONFIG_I2S_CLK_SLAVE_PIN, HAL_PIO_I2S_SCLK);
    uapi_pin_set_mode(CONFIG_I2S_WS_SLAVE_PIN, HAL_PIO_I2S_WS);
    uapi_pin_set_mode(CONFIG_I2S_DO_SLAVE_PIN, HAL_PIO_I2S_DOUT);
    uapi_pin_set_mode(CONFIG_I2S_DI_SLAVE_PIN, HAL_PIO_I2S_DIN);
}

void app_i2s_rx_callbcak(uint32_t *left_buff, uint32_t *right_buff, uint32_t length)
{
    for (uint32_t i = 0; i < length; i++) {
        osal_printk("left rx data is:0x%0x\r\n", left_buff[i]);
        osal_printk("right rx data is:0x%0x\r\n", right_buff[i]);
    }
}

static void *i2s_slave_task(const char *arg)
{
    unused(arg);
    i2s_config_t config = {
        .drive_mode= SLAVE,
        .transfer_mode = STD_MODE,
        .data_width = TWENTY_FOUR_BIT,
        .channels_num = TWO_CH,
        .timing = NONE_MODE,
        .clk_edge = NONE_EDGE,
        .div_number = I2S_DATA_WIDTH,
        .number_of_channels = I2S_NUMBER_OF_CHANNELS,
    };
    app_i2s_init_pin();
    /* I2S init. */
    uapi_i2s_init(CONFIG_I2S_SLAVE_BUS_ID, app_i2s_rx_callbcak);
    uapi_i2s_set_config(CONFIG_I2S_SLAVE_BUS_ID, &config);

    osal_printk("i2s slave read start!\r\n");
    uapi_i2s_read_start(CONFIG_I2S_SLAVE_BUS_ID);

    return NULL;
}

static void i2s_slave_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "I2sSlaveTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = I2S_TASK_STACK_SIZE;
    attr.priority = I2S_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)i2s_slave_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the i2s_slave_entry. */
app_run(i2s_slave_entry);

取两块核心板,将二者的I2S CLK引脚相连,将二者的IS2 WS引脚相连,将一块的I2S DO引脚和另一块的I2S DI引脚相连,同理I2S DI和I2S DO相连,并将二者的GND相连。

输出结果如下:

 

SPI主从数据传输测试

SPI为串行外围设备接口,是一种全双工的同步通信总线,信号线一般有四条:主设备输入/从设备输出(MISO),主设备输出/从设备输入(MOSI),串行时钟信号(SCLK),片选信号(CS)。对于H2821,需要定义时钟引脚CLK,使能引脚CS,输出引脚DO以及输入引脚DI。

代码实现:

对于主设备,需要定义引脚、从设备数量、时钟频率、时钟极性、时钟相位、框架格式、传输数据量等参数:

#include "pinctrl.h"
#include "spi.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define SPI_SLAVE_NUM                   1
#define SPI_FREQUENCY                   2
#define SPI_CLK_POLARITY                0
#define SPI_CLK_PHASE                   0
#define SPI_FRAME_FORMAT                0
#define SPI_FRAME_FORMAT_STANDARD       0
#define SPI_FRAME_SIZE_8                0x1f
#define SPI_TMOD                        0
#define SPI_WAIT_CYCLES                 0x10

#define SPI_TASK_STACK_SIZE             0x1000
#define SPI_TASK_DURATION_MS            1000
#define SPI_TASK_PRIO                   (osPriority_t)(17)

static void app_spi_init_pin(void)
{
    if (CONFIG_SPI_MASTER_BUS_ID == 0) {
        uapi_pin_set_mode(CONFIG_SPI_DI_MASTER_PIN, HAL_PIO_SPI0_RXD);
        uapi_pin_set_mode(CONFIG_SPI_DO_MASTER_PIN, HAL_PIO_SPI0_TXD);
        uapi_pin_set_mode(CONFIG_SPI_CLK_MASTER_PIN, HAL_PIO_SPI0_SCLK);
        uapi_pin_set_mode(CONFIG_SPI_CS_MASTER_PIN, HAL_PIO_SPI0_CS0);      
    }else if (CONFIG_SPI_MASTER_BUS_ID == 1) {
        uapi_pin_set_mode(CONFIG_SPI_DI_MASTER_PIN, HAL_PIO_SPI1_RXD);
        uapi_pin_set_mode(CONFIG_SPI_DO_MASTER_PIN, HAL_PIO_SPI1_TXD);
        uapi_pin_set_mode(CONFIG_SPI_CLK_MASTER_PIN, HAL_PIO_SPI1_CLK);
        uapi_pin_set_mode(CONFIG_SPI_CS_MASTER_PIN, HAL_PIO_SPI1_CS0);     
    }else if (CONFIG_SPI_MASTER_BUS_ID == 2) {
        uapi_pin_set_mode(CONFIG_SPI_DI_MASTER_PIN, HAL_PIO_SPI2_RXD);
        uapi_pin_set_mode(CONFIG_SPI_DO_MASTER_PIN, HAL_PIO_SPI2_TXD);
        uapi_pin_set_mode(CONFIG_SPI_CLK_MASTER_PIN, HAL_PIO_SPI2_CLK);
        uapi_pin_set_mode(CONFIG_SPI_CS_MASTER_PIN, HAL_PIO_SPI2_CS0);         
    }
}

static void app_spi_master_init_config(void)
{
    spi_attr_t config = { 0 };
    spi_extra_attr_t ext_config = { 0 };

    config.is_slave = false;
    config.slave_num = SPI_SLAVE_NUM;
    config.bus_clk = SPI_CLK_FREQ;
    config.freq_mhz = SPI_FREQUENCY;
    config.clk_polarity = SPI_CLK_POLARITY;
    config.clk_phase = SPI_CLK_PHASE;
    config.frame_format = SPI_FRAME_FORMAT;
    config.spi_frame_format = HAL_SPI_FRAME_FORMAT_STANDARD;
    config.frame_size = SPI_FRAME_SIZE_8;
    config.tmod = SPI_TMOD;
    config.sste = 1;

    ext_config.qspi_param.wait_cycles = SPI_WAIT_CYCLES;
    uapi_spi_init(CONFIG_SPI_MASTER_BUS_ID, &config, &ext_config);
}

static void *spi_master_task(const char *arg)
{
    unused(arg);
    /* SPI pinmux. */
    app_spi_init_pin();

    /* SPI master init config. */
    app_spi_master_init_config();

    /* SPI data config. */
    uint8_t tx_data[CONFIG_SPI_TRANSFER_LEN] = { 0 };
    for (uint32_t loop = 0; loop < CONFIG_SPI_TRANSFER_LEN; loop++) {
        tx_data[loop] = (loop & 0xFF);
    }
    uint8_t rx_data[CONFIG_SPI_TRANSFER_LEN] = { 0 };
    spi_xfer_data_t data = {
        .tx_buff = tx_data,
        .tx_bytes = CONFIG_SPI_TRANSFER_LEN,
        .rx_buff = rx_data,
        .rx_bytes = CONFIG_SPI_TRANSFER_LEN,
    };

    while (1) {
        osDelay(SPI_TASK_DURATION_MS);
        osal_printk("spi%d master send start!\r\n", CONFIG_SPI_MASTER_BUS_ID);
        if (uapi_spi_master_write(CONFIG_SPI_MASTER_BUS_ID, &data, 0xFFFFFFFF) == ERRCODE_SUCC) {
            osal_printk("spi%d master send succ!\r\n", CONFIG_SPI_MASTER_BUS_ID);
        } else {
            continue;
        }
        osal_printk("spi%d master receive start!\r\n", CONFIG_SPI_MASTER_BUS_ID);
        if (uapi_spi_master_read(CONFIG_SPI_MASTER_BUS_ID, &data, 0xFFFFFFFF) == ERRCODE_SUCC) {
            for (uint32_t i = 0; i < data.rx_bytes; i++) {
                osal_printk("spi%d master receive data is %x\r\n", CONFIG_SPI_MASTER_BUS_ID, data.rx_buff[i]);
            }
            osal_printk("spi%d master receive succ!\r\n", CONFIG_SPI_MASTER_BUS_ID);
        }
    }

    return NULL;
}

static void spi_master_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "SpiMasterTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = SPI_TASK_STACK_SIZE;
    attr.priority = SPI_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)spi_master_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the spi_master_entry. */
app_run(spi_master_entry);

对于从设备,同样需要定义引脚、从设备数量、时钟频率、时钟极性、时钟相位、框架格式、传输数据量等参数:

#include "pinctrl.h"
#include "spi.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"

#define SPI_SLAVE_NUM                   1
#define SPI_FREQUENCY                   2
#define SPI_CLK_POLARITY                0
#define SPI_CLK_PHASE                   0
#define SPI_FRAME_FORMAT                0
#define SPI_FRAME_FORMAT_STANDARD       0
#define SPI_FRAME_SIZE_8                0x1f
#define SPI_TMOD                        0
#define SPI_WAIT_CYCLES                 0x10

#define SPI_TASK_STACK_SIZE             0x1000
#define SPI_TASK_DURATION_MS            1000
#define SPI_TASK_PRIO                   (osPriority_t)(17)

static void app_spi_init_pin(void)
{

    if (CONFIG_SPI_SLAVE_BUS_ID == 0) {
        uapi_pin_set_mode(CONFIG_SPI_DI_SLAVE_PIN, HAL_PIO_SPI0_RXD);
        uapi_pin_set_mode(CONFIG_SPI_DO_SLAVE_PIN, HAL_PIO_SPI0_TXD);
        uapi_pin_set_mode(CONFIG_SPI_CLK_SLAVE_PIN, HAL_PIO_SPI0_SCLK);
        uapi_pin_set_mode(CONFIG_SPI_CS_SLAVE_PIN, HAL_PIO_SPI0_CS0);      
    }else if (CONFIG_SPI_SLAVE_BUS_ID == 1) {
        uapi_pin_set_mode(CONFIG_SPI_DI_SLAVE_PIN, HAL_PIO_SPI1_RXD);
        uapi_pin_set_mode(CONFIG_SPI_DO_SLAVE_PIN, HAL_PIO_SPI1_TXD);
        uapi_pin_set_mode(CONFIG_SPI_CLK_SLAVE_PIN, HAL_PIO_SPI1_CLK);
        uapi_pin_set_mode(CONFIG_SPI_CS_SLAVE_PIN, HAL_PIO_SPI1_CS0);     
    }else if (CONFIG_SPI_SLAVE_BUS_ID == 2) {
        uapi_pin_set_mode(CONFIG_SPI_DI_SLAVE_PIN, HAL_PIO_SPI2_RXD);
        uapi_pin_set_mode(CONFIG_SPI_DO_SLAVE_PIN, HAL_PIO_SPI2_TXD);
        uapi_pin_set_mode(CONFIG_SPI_CLK_SLAVE_PIN, HAL_PIO_SPI2_CLK);
        uapi_pin_set_mode(CONFIG_SPI_CS_SLAVE_PIN, HAL_PIO_SPI2_CS0);         
    }
}


static void app_spi_slave_init_config(void)
{
    spi_attr_t config = { 0 };
    spi_extra_attr_t ext_config = { 0 };

    config.is_slave = true;
    config.slave_num = SPI_SLAVE_NUM;
    config.bus_clk = SPI_CLK_FREQ;
    config.freq_mhz = SPI_FREQUENCY;
    config.clk_polarity = SPI_CLK_POLARITY;
    config.clk_phase = SPI_CLK_PHASE;
    config.frame_format = SPI_FRAME_FORMAT;
    config.spi_frame_format = HAL_SPI_FRAME_FORMAT_STANDARD;
    config.frame_size = SPI_FRAME_SIZE_8;
    config.tmod = SPI_TMOD;
    config.sste = 1;

    ext_config.qspi_param.wait_cycles = SPI_WAIT_CYCLES;

#if defined(CONFIG_SPI_SUPPORT_DMA) && (CONFIG_SPI_SUPPORT_DMA == 1)
    uapi_dma_init();
    uapi_dma_open();
#endif  /* CONFIG_SPI_SUPPORT_DMA */

    uapi_spi_init(CONFIG_SPI_SLAVE_BUS_ID, &config, &ext_config);
}

static void *spi_slave_task(const char *arg)
{
    unused(arg);
    /* SPI pinmux. */
    app_spi_init_pin();

    /* SPI slave init config. */
    app_spi_slave_init_config();

    /* SPI data config. */
    uint8_t tx_data[CONFIG_SPI_TRANSFER_LEN] = { 0 };
    for (uint32_t loop = 0; loop < CONFIG_SPI_TRANSFER_LEN; loop++) {
        tx_data[loop] = (loop & 0xFF);
    }
    uint8_t rx_data[CONFIG_SPI_TRANSFER_LEN] = { 0 };
    spi_xfer_data_t data = {
        .tx_buff = tx_data,
        .tx_bytes = CONFIG_SPI_TRANSFER_LEN,
        .rx_buff = rx_data,
        .rx_bytes = CONFIG_SPI_TRANSFER_LEN,
    };

    while (1) {
        osDelay(SPI_TASK_DURATION_MS);
        osal_printk("spi%d slave receive start!\r\n", CONFIG_SPI_SLAVE_BUS_ID);
        if (uapi_spi_slave_read(CONFIG_SPI_SLAVE_BUS_ID, &data, 0xFFFFFFFF) == ERRCODE_SUCC) {
            for (uint32_t i = 0; i < data.rx_bytes; i++) {
                osal_printk("spi%d slave receive data is %x\r\n", CONFIG_SPI_SLAVE_BUS_ID, data.rx_buff[i]);
            }
            osal_printk("spi%d slave receive succ!\r\n", CONFIG_SPI_SLAVE_BUS_ID);
        } else {
            continue;
        }
        osal_printk("spi%d slave send start!\r\n", CONFIG_SPI_SLAVE_BUS_ID);
        if (uapi_spi_slave_write(CONFIG_SPI_SLAVE_BUS_ID, &data, 0xFFFFFFFF) == ERRCODE_SUCC) {
            osal_printk("spi%d slave send succ!\r\n", CONFIG_SPI_SLAVE_BUS_ID);
        }
    }

    return NULL;
}

static void spi_slave_entry(void)
{
    osThreadAttr_t attr;

    attr.name = "SpiSlaveTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = SPI_TASK_STACK_SIZE;
    attr.priority = SPI_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)spi_slave_task, NULL, &attr) == NULL) {
        /* Create task fail. */
    }
}

/* Run the spi_slave_entry. */
app_run(spi_slave_entry);

取两块核心板,将二者的SPI CLK引脚相连,将二者的SPI CS引脚相连,将一块的SPI DO引脚与另一块的SPI DI引脚相连,同理SPI DI与SPI DO相连,将二者的GND相连。

输出结果如下:

 

此帖出自RF/无线论坛

最新回复

这个可以连星闪吗,功率够不够  详情 回复 发表于 2024-8-21 14:20
点赞 关注
 

回复
举报

6788

帖子

2

TA的资源

版主

沙发
 

这么说只有一个串口能用,确实有点少。

此帖出自RF/无线论坛

点评

确实少了点,但是咱们不是冲它无线蓝牙去的嘛  详情 回复 发表于 2024-8-19 20:38
 
 

回复

26

帖子

2

TA的资源

一粒金砂(中级)

板凳
 
wangerxian 发表于 2024-8-19 17:52 这么说只有一个串口能用,确实有点少。

确实少了点,但是咱们不是冲它无线蓝牙去的嘛

此帖出自RF/无线论坛

点评

倒也是,可以测试测试星闪功能~  详情 回复 发表于 2024-8-20 09:04
 
 
 

回复

6788

帖子

2

TA的资源

版主

4
 
FuShenxiao 发表于 2024-8-19 20:38 确实少了点,但是咱们不是冲它无线蓝牙去的嘛

倒也是,可以测试测试星闪功能~

此帖出自RF/无线论坛
 
 
 

回复

10

帖子

0

TA的资源

一粒金砂(中级)

5
 
这个可以连星闪吗,功率够不够
此帖出自RF/无线论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表