查时序也没有问题啊,为什么呢?
你首先检查晶振以及复位是否好?还有你配置SPI的时候有没有配置正确,包括我们的芯片进入SPI模式的必须的配置。
检查CH376硬件连接没有问题,上电之后先延时50ms 在操作, 时序上面片选为低之后的第一个字节作为命令处理。
晶振和复位都测过了,没有问题. SPI怎么配置啊?手册上的方法不一样,我都试了,不行. 因为我是调试,上电之后先延时50ms肯定能保证的.
我读回了0X5F,代表命令失败,是不是证明SPI通讯是对的?
这个结果表示通讯测试是失败的 把底层SPI接口程序贴出来
void CH376_PORT_INIT( void ) /* 由于使用软件模拟SPI读写时序,所以进行初始化 */ { /* 如果是硬件SPI接口,那么可使用mode3(CPOL=1&CPHA=1)或mode0(CPOL=0&CPHA=0),CH376在时钟上升沿采样输入,下降沿输出,数据位是高位在前 */ //CH376_SPI_SCS = 1; /* 禁止SPI片选 */ IOWR_ALTERA_AVALON_PIO_DATA(CH_SCS_BASE, 1); IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 1); //CH376_SPI_SCK = 1; /* 默认为高电平,SPI模式3,也可以用SPI模式0,但模拟程序可能需稍做修改 */ /* 对于双向I/O引脚模拟SPI接口,那么必须在此设置SPI_SCS,SPI_SCK,SPI_SDI为输出方向,SPI_SDO为输入方向 */ }
void mDelay0_5uS( void ) /* 至少延时0.5uS,根据单片机主频调整 */ { int i; for(i=0;i<5;i++); }
void Spi376OutByte( UINT8 d ) /* SPI输出8个位数据 */ { /* 如果是硬件SPI接口,应该是先将数据写入SPI数据寄存器,然后查询SPI状态寄存器以等待SPI字节传输完成 */ UINT8 i; for ( i = 0; i < 8; i ++ ) { IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 0); if ( d & 0x80 ) IOWR_ALTERA_AVALON_PIO_DATA(CH_SDO_BASE, 1); else IOWR_ALTERA_AVALON_PIO_DATA(CH_SDO_BASE, 0); d <<= 1; /* 数据位是高位在前 */ IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 1); /* CH376在时钟上升沿采样输入 */ } }
UINT8 Spi376InByte( void ) /* SPI输入8个位数据 */ { /* 如果是硬件SPI接口,应该是先查询SPI状态寄存器以等待SPI字节传输完成,然后从SPI数据寄存器读出数据 */ UINT8 i, d; d = 0; for ( i = 0; i < 8; i ++ ) { IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 0); /* CH376在时钟下降沿输出 */ d <<= 1; /* 数据位是高位在前 */ if (IORD_ALTERA_AVALON_PIO_DATA(CH_SDI_BASE) ) d ++; IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 1); } return( d ); }
#define xEndCH376Cmd( ) { IOWR_ALTERA_AVALON_PIO_DATA(CH_SCS_BASE, 1); } /* SPI片选无效,结束CH376命令,仅用于SPI接口方式 */
void xWriteCH376Cmd( UINT8 mCmd ) /* 向CH376写命令 */ { #ifdef CH376_SPI_BZ UINT8 i; #endif IOWR_ALTERA_AVALON_PIO_DATA(CH_SCS_BASE, 1); /* 防止之前未通过xEndCH376Cmd禁止SPI片选 */ mDelay0_5uS( ); /* 对于双向I/O引脚模拟SPI接口,那么必须确保已经设置SPI_SCS,SPI_SCK,SPI_SDI为输出方向,SPI_SDO为输入方向 */ IOWR_ALTERA_AVALON_PIO_DATA(CH_SCS_BASE, 0); /* SPI片选有效 */ Spi376OutByte( mCmd ); /* 发出命令码 */ #ifdef CH376_SPI_BZ for ( i = 30; i != 0 && CH376_SPI_BZ; -- i ); /* SPI忙状态查询,等待CH376不忙,或者下面一行的延时1.5uS代替 */ #else mDelay0_5uS( ); mDelay0_5uS( ); mDelay0_5uS( ); mDelay0_5uS( );/* 延时1.5uS确保读写周期大于1.5uS,或者用上面一行的状态查询代替 */ #endif }
#ifdef FOR_LOW_SPEED_MCU /* 不需要延时 */ #define xWriteCH376Data( d ) { Spi376OutByte( d ); } /* 向CH376写数据 */ #define xReadCH376Data( ) ( Spi376InByte( ) ) /* 从CH376读数据 */ #else void xWriteCH376Data( UINT8 mData ) /* 向CH376写数据 */ { Spi376OutByte( mData ); mDelay0_5uS( ); /* 确保读写周期大于0.6uS */ } UINT8 xReadCH376Data( void ) /* 从CH376读数据 */ { /* 确保读写周期大于0.6uS */ return( Spi376InByte( ) ); mDelay0_5uS( ); } #endif
/* 查询CH376中断(INT#低电平) */ UINT8 Query376Interrupt( void ) { //#ifdef CH376_INT_WIRE // return( CH376_INT_WIRE ? FALSE : TRUE ); /* 如果连接了CH376的中断引脚则直接查询中断引脚 */ //#else // return( CH376_SPI_SDO ? FALSE : TRUE ); /* 如果未连接CH376的中断引脚则查询兼做中断输出的SDO引脚状态 */ //#endif return 0; }
UINT8 mInitCH376Host( void ) /* 初始化CH376 */ { UINT8 res; CH376_PORT_INIT( ); /* 接口硬件初始化 */ xWriteCH376Cmd( CMD11_CHECK_EXIST ); /* 测试单片机与CH376之间的通讯接口 */ xWriteCH376Data( 0x65 ); res = xReadCH376Data( ); xEndCH376Cmd( ); printf("CMD11_CHECK_EXIST=%x!\n",res); if ( res != 0x9A ) { printf("Error!!!!!\n"); return( ERR_USB_UNKNOWN ); /* 通讯接口不正常,可能原因有:接口连接异常,其它设备影响(片选不唯一),串口波特率,一直在复位,晶振不工作 */ } xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 设备USB工作模式 */ xWriteCH376Data( 0x06 ); mDelayuS( 20 ); res = xReadCH376Data( ); xEndCH376Cmd( ); #ifndef CH376_INT_WIRE #ifdef CH376_SPI_SDO xWriteCH376Cmd( CMD20_SET_SDO_INT ); /* 设置SPI的SDO引脚的中断方式 */ xWriteCH376Data( 0x16 ); xWriteCH376Data( 0x90 ); /* SDO引脚在SCS片选无效时兼做中断请求输出 */ xEndCH376Cmd( ); #endif #endif if ( res == CMD_RET_SUCCESS ) return( USB_INT_SUCCESS ); else return( ERR_USB_UNKNOWN ); /* 设置模式错误 */ } int main() { int i,j; printf("Hello from Nios II!\n"); i=0x55; IOWR(SDRAM_BASE,0,i); j=IORD(SDRAM_BASE,0); printf("j=%d!\n",j); //ALTERA_AVALON_SPI_INIT(CH_SPI_BASE, 1); //alt_avalon_spi_command(CH_SPI_BASE,0,16,wrdata,0,NULL,0); //IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(CH_SPI_BASE, 1 << 0); // IOWR_ALTERA_AVALON_SPI_CONTROL(CH_SPI_BASE, ALTERA_AVALON_SPI_CONTROL_SSO_MSK); // IORD_ALTERA_AVALON_SPI_RXDATA(CH_SPI_BASE); // ALTERA_AVALON_SPI_INIT(CH_SPI_BASE, 0);
//SetUsbMode(); while(1) { //IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 0); //IOWR_ALTERA_AVALON_PIO_DATA(CH_SCK_BASE, 1); //GetCH376Exist(); mInitCH376Host(); // mDelayuS(100); }
return 0; }
这个程序是用DEMO里的程序改的,基本上就是改的接口部分,用示波器量过波形,没发现问题.很郁闷.
CH_SDO_BASE、CH_SDI_BASE是不是连接CH376的SDO和SDI?如果是这样,那么就错了,这2个引脚需要交换一下 你对比一下SPI_SW中Spi376OutByte,Spi376InByte是操作哪个引脚的
CH_SDO_BASE-SDI CH_SDI_BASE-SDO 只不过取名字的时候取反了
CH_SDO_BASE对是我的输出,CH_SDI是输入.
如果不给376模块供电,我读回来的就是0X00,上电就是0X5F
用示波器看看时序吧,默认的时候CH376的SCS应该是高电平。