#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