小熊派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码值。
需要特别注意的是:
- H2821虽然有三个UART,但是UART0用于烧录和日志打印;UART1用于协议栈的日志打印,需要配套特殊工具才能看到;只有UART2是闲置的,因此在串口调试时,除去日志打印,最好使用UART2
- 在设置数据位长度时,代码为" #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相连。
输出结果如下:
|