223 lines
7.3 KiB
C
223 lines
7.3 KiB
C
#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
|