doubao_chat/apps/common/example/peripheral/spi/spi_1bit/main.c

223 lines
7.3 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "app_config.h"
#include "system/includes.h"
#include "device/device.h"
#include "asm/spi.h"
#include "device/gpio.h"
#ifdef USE_1BIT_TSET_DEMO
//定义中断回调函数
void spi_irq_cb(void *priv, u8 **data, u32 *len)
{
putchar('@');
}
static void spi_test_task(void *p)
{
char *buf = NULL;
struct spi_user su = {0};
void *spi_hdl = NULL;
int ret;
int read_addr;
#if 1
/* 使用方法1:接收固定数据量,比如接收固定的SPI摄像头数据。
如:SPI摄像宽为128,高为224,仅传输Y灰度数据,一帧数据头为4字节,
一帧数据尾为4字节,摄像头进行一行一行数据往SPI发送数据,则当
一帧数据量小于65535时,SPI从机配置如下:
*/
int w = 128;
int h = 224;
int fhead = 4;
int fend = 4;
int line_size = w;//一行的数据(此处为Y,当数据为Y+U+V的YUV422时,line_size = w * 2)
int frame_size = line_size * h + fhead + fend;//一帧的数据(此处为Y,当数据为Y+U+V的YUV422时,frame_size = line_size * h * 2 + fhead + fend)
//----------------用户指定接收块大小配置--------------------------//
/*1.当一帧数据量<=SPI_MAX_SIZE,则可以接收完整的一帧
当一帧数据量>SPI_MAX_SIZE,则先接收一部分,再偏移地址接收一部分(内部系统完成,应用层不用关注)
当芯片为AC790N则SPI_MAX_SIZE = 65535,当芯片为AC791N则SPI_MAX_SIZE = 2^31
*/
//first_dma_size第一次接收数据量:一帧数据量<=SPI_MAX_SIZE,可设置第一次DMA数据量为一帧或者0,当一帧数据量>SPI_MAX_SIZE,第一次接收为:帧头 + 行的整数倍
su.first_dma_size = (frame_size > SPI_MAX_SIZE) ? (SPI_MAX_SIZE / line_size * line_size + fhead) : frame_size;
//dma最大个数为spi的最大dma字节
su.dma_max_cnt = SPI_MAX_SIZE;
//一个块的大小(分块在此处即为一帧大小)
su.block_size = frame_size;
//指定接收的缓冲区为一个块大小(此处为一帧)的2倍以上,此处为2倍
su.buf_size = frame_size * 2;
//申请缓冲区
su.buf = malloc(su.buf_size);
if (!su.buf) {
printf("err spi no buf \n");
goto exit;
}
//2.打开spi设备
spi_hdl = dev_open("spi1", NULL);
if (!spi_hdl) {
printf("spi open err \n");
goto exit;
}
//3.设置:用户指定接收块大小配置信息,使用IOCTL_SPI_SET_USER_INFO时不能使用IOCTL_SPI_SET_CB注册回调函数
dev_ioctl(spi_hdl, IOCTL_SPI_SET_USER_INFO, (u32)&su);
dev_ioctl(spi_hdl, IOCTL_SPI_SET_IRQ_CPU_ID, (u32)1);//可以指定中断到核1执行
while (1) {
//4.读取数据,注意:IOCTL_SPI_READ_DATA启用读取数据之前需保证此时对方SPI还没有发送数据,否则中途接收数据会出错
ret = dev_ioctl(spi_hdl, IOCTL_SPI_READ_DATA, (u32)&read_addr);
if (ret > 0) {//返回值大于0则已经读取到数据
//5. read_addr的值就是硬件存放数据在su.buf的可用地址,ret则为可用地址read_addr的数据量大小
//todo
put_buf((u8 *)read_addr, ret); //打印数据
//6.用完释放数据
dev_ioctl(spi_hdl, IOCTL_SPI_FREE_DATA, 0);
}
}
#endif
/* 使用方法1:单次指定接收固定数据量。
注意:此方法spi接收数据比较慢,因此对方主机的spi连续发送字节不能过快,否则丢数据(当数对方主机spi数据过快,请使用上述:用户指定接收块方法)
*/
//1.打开spi设备
spi_hdl = dev_open("spi1", NULL);
if (!spi_hdl) {
printf("spi open err \n");
goto exit;
}
//2.注册回调函数
struct spi_cb cb;
cb.cb_func = spi_irq_cb;//回调函数
cb.cb_priv = NULL;//回调函数的第一个私有参数
dev_ioctl(spi_hdl, IOCTL_SPI_SET_CB, (u32)&cb);
dev_ioctl(spi_hdl, IOCTL_SPI_SET_IRQ_CPU_ID, (u32)1);//可以指定中断到核1执行
dev_ioctl(spi_hdl, IOCTL_SPI_SET_USE_SEM, 0);//等待数据时,用信号量等待,不用则为抢占查询硬件中断标记,建议应信号量等待
//3.发送一个字节,有发送字节的board.c需配置为使用DO和DI数据线
u8 data = 0x12;
dev_ioctl(spi_hdl, IOCTL_SPI_SEND_BYTE, data);//发送一个字节
//4.读取一个字节
data = dev_ioctl(spi_hdl, IOCTL_SPI_READ_BYTE, 0);//读取一个字节
buf = malloc(1024);
if (!buf) {
printf("err spi no buf \n");
goto exit;
}
while (1) {
//5.固定读取1024字节,注意当读取满1024字节时,需要任务调度此处才能返回去执行收数应用层操作,因此对方主机SPI发送完1024字节时,一般需要等待几个ms以上才能再次发固定数据
ret = dev_read(spi_hdl, buf, 1024);
if (ret == 0) {//返回值=0则已经读取到数据
//6. 数据存在buf,长度为1024
//todo
put_buf(buf, 1024);//打印数据
}
}
exit:
if (su.buf) { //释放内存
free(su.buf);
}
if (buf) { //释放内存
free(buf);
}
if (spi_hdl) { //关闭spi设备
dev_close(spi_hdl);
}
while (1) { //等待其他任务杀此任务
os_time_dly(100);
}
}
static int c_main(void)
{
os_task_create(spi_test_task, NULL, 22, 1000, 0, "spi_test_task");
return 0;
}
late_initcall(c_main);
#endif
#ifdef USE_SPI_LCD_1BIT_TEST
//说明该测试例子为spi1线推屏接口测试 最要用于测试接口推屏能力
//需要将isd_config_rule.c
//LSB_DIV=1; [低速总线时钟分频系数 LSB_DIV+1]
//测试结果 320*240 1bit推屏帧率 44帧
/* SPI2_PLATFORM_DATA_BEGIN(spi2_data) */
/* .clk = 80000000, */
/* .mode = SPI_1WIRE_MODE, */
/* .port = 'C', */
/* .attr = SPI_SCLK_L_UPH_SMPH | SPI_UNIDIR_MODE , */
/* SPI2_PLATFORM_DATA_END() */
#define SPI_LEN 320*240*2
static void Calculation_frame(void)
{
static u32 tstart = 0, tdiff = 0;
static u8 fps_cnt = 0;
fps_cnt++ ;
if (!tstart) {
tstart = timer_get_ms();
} else {
tdiff = timer_get_ms() - tstart;
if (tdiff >= 1000) {
printf("\n [MSG]fps_count = %d\n", fps_cnt * 1000 / tdiff);
tstart = 0;
fps_cnt = 0;
}
}
}
SEC_USED(.sram) static u8 data[320 * 240 * 2] ;
static void spi_test_task(void *p)
{
void *spi_hdl = NULL;
//1.打开spi设备
spi_hdl = dev_open("spi2", NULL);
if (!spi_hdl) {
printf("spi open err \n");
goto exit;
}
memset(data, 0x55, 320 * 240 * 2);
dev_ioctl(spi_hdl, IOCTL_SPI_NON_BLOCK, 0);//设置为非阻塞发送数据包
while (1) {
dev_write(spi_hdl, data, 1);//发送1bit使用该接口
dev_write(spi_hdl, data, 1);//发送1bit使用该接口
dev_write(spi_hdl, data, 1);//发送1bit使用该接口
/* os_time_dly(1); */
dev_write(spi_hdl, data, SPI_LEN);
Calculation_frame();
/* os_time_dly(1); */
yield();//clear sys dog
}
exit:
if (spi_hdl) { //关闭spi设备
dev_close(spi_hdl);
}
while (1) { //等待其他任务杀此任务
os_time_dly(100);
}
}
static int c_main(void)
{
os_task_create(spi_test_task, NULL, 22, 1000, 0, "spi_test_task");
return 0;
}
late_initcall(c_main);
#endif