278 lines
7.4 KiB
C
278 lines
7.4 KiB
C
#include "system/includes.h"
|
||
#include "media/includes.h"
|
||
#include "asm/spi.h"
|
||
#include "generic/log.h"
|
||
|
||
#if 0
|
||
/*
|
||
[[[ README ]]]
|
||
1. 本spi测试demo提供了spi.c的API使用例程,测试方式为两个spi的环回测试。
|
||
spi1设置为主机模式,spi2设置为从机模式,spi1发送数据到spi2,然后接收spi2
|
||
原样返回的数据,然后比较发送出去的数据与接收的数据是否一致,一致则说明
|
||
验证通过。
|
||
2. 本demo涉及BYTE收发测试及DMA收发测试,通过宏SPI_TEST_MODE选择。另外
|
||
demo还涉及到spi中断中调用可用于中断的spi API的使用。
|
||
3. spi.c的API不包含CS引脚,CS由API以外控制。
|
||
4. 请在board_xxx.c中定义配置结构体,例如用到spi1,需要定义spi1_p_data,
|
||
否则编译出错。
|
||
5. spi的DMA地址需要4字节对齐。
|
||
6. 虽然spi.c的API带有spi0,但在有挂spi flash的芯片上使用可能会出问题,
|
||
避免使用spi0。
|
||
|
||
*/
|
||
|
||
#define SPI1_CS_OUT() \
|
||
do { \
|
||
JL_PORTB->DIR &= ~BIT(4); \
|
||
JL_PORTB->DIE |= BIT(4); \
|
||
JL_PORTB->PU &= ~BIT(4); \
|
||
JL_PORTB->PD &= ~BIT(4); \
|
||
} while(0)
|
||
#define SPI1_CS_L() (JL_PORTB->OUT &= ~BIT(4))
|
||
#define SPI1_CS_H() (JL_PORTB->OUT |= BIT(4))
|
||
|
||
#define SPI2_CS_IN() \
|
||
do { \
|
||
JL_PORTA->DIR |= BIT(3); \
|
||
JL_PORTA->DIE |= BIT(3); \
|
||
JL_PORTA->PU &= ~BIT(3); \
|
||
JL_PORTA->PD &= ~BIT(3); \
|
||
} while (0)
|
||
#define SPI2_READ_CS() (JL_PORTA->IN & BIT(3))
|
||
|
||
static u8 slave_dir = 1;
|
||
static u8 spi1_send_buf[100] __attribute__((aligned(4)));
|
||
static u8 spi1_recv_buf[100] __attribute__((aligned(4)));
|
||
static u8 spi2_send_buf[100] __attribute__((aligned(4)));
|
||
static u8 spi2_recv_buf[100] __attribute__((aligned(4)));
|
||
|
||
static spi_dev spi1_hdl = 1;
|
||
static spi_dev spi2_hdl = 2;
|
||
|
||
#define SPI_TEST_BYTE_MODE 0x01
|
||
#define SPI_TEST_DMA_MODE 0x02
|
||
//测试模式选择
|
||
#define SPI_TEST_MODE SPI_TEST_BYTE_MODE
|
||
|
||
static void my_put_u8hex(u8 b)
|
||
{
|
||
u8 dat;
|
||
dat = b / 16;
|
||
if (dat >= 0 && dat <= 9) {
|
||
putchar('0' + dat);
|
||
} else {
|
||
putchar('A' + dat - 10);
|
||
}
|
||
dat = b % 16;
|
||
if (dat >= 0 && dat <= 9) {
|
||
putchar('0' + dat);
|
||
} else {
|
||
putchar('A' + dat - 10);
|
||
}
|
||
putchar(' ');
|
||
}
|
||
|
||
//中断函数,需以下特殊声明
|
||
__attribute__((interrupt("")))
|
||
static void spi2_isr()
|
||
{
|
||
static int i = 0;
|
||
if (spi_get_pending(spi2_hdl)) {
|
||
spi_clear_pending(spi2_hdl);
|
||
if (SPI2_READ_CS()) {
|
||
return;
|
||
}
|
||
#if SPI_TEST_MODE == SPI_TEST_BYTE_MODE
|
||
if (slave_dir == 1) {
|
||
spi2_recv_buf[i] = spi_recv_byte_for_isr(spi2_hdl);
|
||
spi_send_byte_for_isr(spi2_hdl, spi2_recv_buf[i]);
|
||
i >= 100 ? i = 0 : i++;
|
||
slave_dir = 0;
|
||
} else {
|
||
slave_dir = 1;
|
||
}
|
||
#elif SPI_TEST_MODE == SPI_TEST_DMA_MODE
|
||
if (slave_dir == 1) {
|
||
spi_dma_set_addr_for_isr(spi2_hdl, spi2_recv_buf, 100, 0);
|
||
slave_dir = 0;
|
||
} else {
|
||
slave_dir = 1;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
#if 1 //仅用于spi demo,正式工程请放到board_xxx.c文件中
|
||
/* const struct spi_platform_data spi0_p_data = { */
|
||
/* .port = 'A', */
|
||
/* .mode = SPI_MODE_BIDIR_1BIT, */
|
||
/* .clk = 1000000, */
|
||
/* .role = SPI_ROLE_MASTER, */
|
||
/* }; */
|
||
|
||
const struct spi_platform_data spi1_p_data = {
|
||
.port = 'A',
|
||
.mode = SPI_MODE_BIDIR_1BIT,
|
||
.clk = 1000000,
|
||
.role = SPI_ROLE_MASTER,
|
||
};
|
||
|
||
const struct spi_platform_data spi2_p_data = {
|
||
.port = 'A',
|
||
.mode = SPI_MODE_BIDIR_1BIT,
|
||
.clk = 1000000,
|
||
.role = SPI_ROLE_SLAVE,
|
||
};
|
||
#endif
|
||
|
||
|
||
void spi_test_main()
|
||
{
|
||
int i;
|
||
int err;
|
||
|
||
spi_open(spi1_hdl);
|
||
spi_open(spi2_hdl);
|
||
spi_set_ie(spi2_hdl, 1);
|
||
//配置中断优先级,中断函数
|
||
request_irq(IRQ_SPI2_IDX, 3, spi2_isr, 0);
|
||
|
||
SPI1_CS_OUT();
|
||
SPI2_CS_IN();
|
||
SPI1_CS_H();
|
||
for (i = 0; i < 100; i++) {
|
||
spi1_send_buf[i] = i % 26 + 'A';
|
||
spi1_recv_buf[i] = 0;
|
||
}
|
||
puts(">>> spi test start\n");
|
||
#if SPI_TEST_MODE == SPI_TEST_BYTE_MODE
|
||
SPI1_CS_L();
|
||
for (i = 0; i < 100; i++) {
|
||
err = spi_send_byte(spi1_hdl, spi1_send_buf[i]);
|
||
if (err) {
|
||
puts("spi1 byte send timeout\n");
|
||
break;
|
||
}
|
||
delay(100);
|
||
spi1_recv_buf[i] = spi_recv_byte(spi1_hdl, &err);
|
||
if (err) {
|
||
puts("spi1 byte recv timeout\n");
|
||
break;
|
||
}
|
||
delay(100);
|
||
}
|
||
SPI1_CS_H();
|
||
#elif SPI_TEST_MODE == SPI_TEST_DMA_MODE
|
||
spi_dma_set_addr_for_isr(spi2_hdl, spi2_recv_buf, 100, 1);
|
||
SPI1_CS_L();
|
||
err = spi_dma_send(spi1_hdl, spi1_send_buf, 100);
|
||
if (err < 0) {
|
||
puts("spi1 dma send timeout\n");
|
||
goto __out_dma;
|
||
}
|
||
//delay(100);
|
||
err = spi_dma_recv(spi1_hdl, spi1_recv_buf, 100);
|
||
if (err < 0) {
|
||
puts("spi1 dma recv timeout\n");
|
||
goto __out_dma;
|
||
}
|
||
//delay(100);
|
||
__out_dma:
|
||
SPI1_CS_H();
|
||
#endif
|
||
puts("<<< spi test end\n");
|
||
|
||
puts("\nspi master receivce buffer:\n");
|
||
for (i = 0; i < 100; i++) {
|
||
//my_put_u8hex(spi1_recv_buf[i]);
|
||
putchar(spi1_recv_buf[i]), putchar(0x20);
|
||
if (i % 16 == 15) {
|
||
putchar('\n');
|
||
}
|
||
}
|
||
if (i % 16) {
|
||
putchar('\n');
|
||
}
|
||
|
||
if (!memcmp(spi1_send_buf, spi1_recv_buf, 100)) {
|
||
puts("\nspi test pass\n");
|
||
} else {
|
||
puts("\nspi test fail\n");
|
||
}
|
||
|
||
spi_close(spi1_hdl);
|
||
spi_close(spi2_hdl);
|
||
}
|
||
|
||
#else
|
||
|
||
//蓝牙SPI debug时打开
|
||
#if 0
|
||
/* 配置要使用的 CS 脚 */
|
||
/* 为了省IO其实可以不用CS脚也能被ellisys分辨出来,或者在ellisys端将CS脚接地 */
|
||
#define SPI1_PORT JL_PORTA
|
||
#define SPI1_PORT_BIT 1
|
||
#define SPI1_CS_OUT() \
|
||
do { \
|
||
SPI1_PORT->DIR &= ~BIT(SPI1_PORT_BIT); \
|
||
SPI1_PORT->DIE |= BIT(SPI1_PORT_BIT); \
|
||
SPI1_PORT->PU &= ~BIT(SPI1_PORT_BIT); \
|
||
SPI1_PORT->PD &= ~BIT(SPI1_PORT_BIT); \
|
||
} while(0)
|
||
#define SPI1_CS_L() (SPI1_PORT->DIR &= ~BIT(SPI1_PORT_BIT),SPI1_PORT->OUT &= ~BIT(SPI1_PORT_BIT))
|
||
#define SPI1_CS_H() (SPI1_PORT->DIR &= ~BIT(SPI1_PORT_BIT),SPI1_PORT->OUT |= BIT(SPI1_PORT_BIT))
|
||
|
||
typedef const int spi_dev;
|
||
|
||
extern int spi_open(spi_dev spi);
|
||
extern int spi_dma_send(spi_dev spi, const void *buf, u32 len);
|
||
|
||
const struct spi_platform_data spi2_p_data = {
|
||
.port = {
|
||
IO_PORTA_02, //CLK
|
||
IO_PORTA_03, //DO
|
||
IO_PORTA_01, //DI
|
||
},
|
||
.mode = SPI_MODE_BIDIR_1BIT,
|
||
.clk = 5000000,
|
||
.role = SPI_ROLE_MASTER,
|
||
};
|
||
|
||
const struct spi_platform_data spi1_p_data = {
|
||
.port = 'B',
|
||
/* .port = { */
|
||
/* #<{(| IO_PORTC_00, // CLK |)}># */
|
||
/* #<{(| IO_PORTC_01, // DO,对应ellisys的DI |)}># */
|
||
/* #<{(| IO_PORTC_02, // DI,对应ellisys的DO |)}># */
|
||
/* */
|
||
/* IO_PORTA_05, // */
|
||
/* IO_PORTA_06, // */
|
||
/* IO_PORTA_07, // */
|
||
/* }, */
|
||
.mode = SPI_MODE_BIDIR_1BIT,
|
||
.clk = 5000000, /* 经测试 ellisys 能分辨到这个速度 */
|
||
.role = SPI_ROLE_MASTER,
|
||
};
|
||
|
||
static spi_dev spi1_hdl = 1;
|
||
static u8 spi1_send_buf[512] ALIGNED(4);
|
||
|
||
void bb_spi_init(void)
|
||
{
|
||
r_printf("spi_open:%08x\n", spi_open);
|
||
spi_open(spi1_hdl);
|
||
/* SPI1_CS_OUT(); */
|
||
/* SPI1_CS_H(); */
|
||
}
|
||
|
||
void bb_spi_send(const void const *buf, size_t len)
|
||
{
|
||
memcpy(spi1_send_buf, buf, len);
|
||
/* SPI1_CS_L(); */
|
||
spi_dma_send(spi1_hdl, spi1_send_buf, len);
|
||
/* SPI1_CS_H(); */
|
||
}
|
||
|
||
#endif
|
||
#endif
|