在很久很久以前(40天前),我画了个PCB,主控芯片用的是ADuC7026 然后...一个PCB竟然做了这么久,不得不佩服下这家工厂- -...
好不容易搭好了硬件,没想到软件上又出问题了...花了N天被这个神奇的SPI接口搞得头晕目眩还是没搞定...(下面我附上了连接图)
然后是“症状”: 我在调试的时候使用Master模式发送,这个地方就比较奇怪了...因为发送对象是2片级联的74HC595,所以要发2个字节,那么我的程序中就这么做了,结果老不正常,然后我意外得发现在末尾跟着发8个“0”就能发送正常(第一个晕倒的地方,到现在还没弄明白..) 然后是最头疼的Master模式接收,这个还要恶心...我设置成接收的那个8位寄存器满了,中断寄存器里的一个位就置1,然后发3个字节空数据(也就是24个时钟)出去,3片165级联所对应的数据就分3次从MISO读进来了。结果人算不如天算啊,用while去等这个1,然后运行时发现...我这辈子是等不到这个1了T_T...之后没办法,只好在发空数据把165数据从MISO上移进来的时候设置成用while查询发送中断位(就是发送寄存器发光了SPI中断寄存器里就有个1出来)结果这个1我是等到了,然后好不容易读进来数据了,然后又出现那个非常奇怪的问题...很不正常,但是在开头先发1个空字节(8个脉冲)出去,不读,然后再发3个空字节(24个脉冲出去),读3次,这样总算是读进来了,也算正常了。但是好景不长,我惊人得发现~~这个神奇的SPI在同样的输入下,连续快速得读100遍,这数据就不是整体向前就是整体向后移动几位,非常可恶...然后在这100次读函数调用的每个后面都加上while(InputDelay--);后,我又惊人得发现当InputDelay大于40的时候(我是41.78M时钟,延时大于40个周期)读进来的数据是正确的(多少遍都一样),但是没有这个延时,数据就前后移动走样........ 晕啊~~我是郁闷死了ADI你真厉害能制造出这么有创意的SPI接口... 以下附上我的程序:
/********************************************************************************************************* * * 这个是发送程序 * *********************************************************************************************************/
extern void DOutputWrite(uint32 OutputData) { SPICON = (1 << 12)| // Continuous Transfer Enable 1 - Enable 0 - Disable (0 << 11)| // Loop Back Enable 1 - Connect test software 0 - Normal mode (0 << 10)| // Slave Output Enable 1 - Enable 0 - Disable (0 << 9)| // Slave Select Input Enable 1 - Enable(Master Mode) 0 - Disable (0 << 8)| // SPIRX Overflow Overwrite Enable 1 - Overwritten 0 - New byte is discarded (0 << 7)| // SPITX Underflow Mode 1 - Transmit 0 0 - Transmit the previous data (1 << 6)| // Tranfer and Interrupt (Master)Mode 1 - SPITX 0 - SPIRX (1 << 5)| // LSB First Transfer Enable Bit 1 - LSB first 0 - MSB first (0 << 3)| // Serial Clock Polarity Mode Bit 1 - Clock idles high 0 - Clock idles low (1 << 2)| // Serial Clock Phase Mode Bit 1 - Begin of bit transfer 0 - End of bit transfer (1 << 1)| // Master Mode Enable Bit 1 - Master mode 0 - Slave mode (1 << 0); // SPI Enable Bit 1 - Enable 0 - Disable
SPITX = ~(OutputData & 0x000000FF); while ((SPISTA & 0x02) != 0x02); // wait for data transfer status bit
SPITX = ~((OutputData & 0x0000FF00) >> 8); while ((SPISTA & 0x02) != 0x02);
SPITX = 0x00; // 这个就是那邪恶的8个空脉冲 while ((SPISTA & 0x02) != 0x02);
CLR_595_STR(); SET_595_STR();
}
/********************************************************************************************************* * * 这个是可恶的接收程序 * *********************************************************************************************************/
extern uint32 DInputRead(void) { uint32 InputData = 0, InputDelay = 100;
SPICON = (1 << 12)| // Continuous Transfer Enable 1 - Enable 0 - Disable (0 << 11)| // Loop Back Enable 1 - Connect test software 0 - Normal mode (0 << 10)| // Slave Output Enable 1 - Enable 0 - Disable (0 << 9)| // Slave Select Input Enable 1 - Enable(Master Mode) 0 - Disable (1 << 8)| // SPIRX Overflow Overwrite Enable 1 - Overwritten 0 - New byte is discarded (0 << 7)| // SPITX Underflow Mode 1 - Transmit 0 0 - Transmit the previous data (1 << 6)| // Tranfer and Interrupt (Master)Mode 1 - SPITX 0 - SPIRX (1 << 5)| // LSB First Transfer Enable Bit 1 - LSB first 0 - MSB first (0 << 3)| // Serial Clock Polarity Mode Bit 1 - Clock idles high 0 - Clock idles low (0 << 2)| // Serial Clock Phase Mode Bit 1 - Begin of bit transfer 0 - End of bit transfer (1 << 1)| // Master Mode Enable Bit 1 - Master mode 0 - Slave mode (1 << 0); // SPI Enable Bit 1 - Enable 0 - Disable
SET_165_SHIFT(); CLR_165_CINH();
SPITX = 0x00; // 那可恶的8个脉冲又登场了 while ((SPISTA & 0x02) != 0x02); // wait for data transfer status bit SPITX = 0x00; while ((SPISTA & 0x02) != 0x02); InputData += SPIRX;
SPITX = 0x00; while ((SPISTA & 0x02) != 0x02); InputData += (SPIRX << 8); SPITX = 0x00; while ((SPISTA & 0x02) != 0x02); InputData += (SPIRX << 16);
CLR_165_SHIFT(); SET_165_CINH();
while(InputDelay--); //这个地方要等大于40个以上周期,不等就出错,郁闷
return InputData; }
/********************************************************************************************************* * * 这个是初始化程序,应该没问题吧.. * *********************************************************************************************************/ extern void DIOInit(void) { // Set GPIO Mode GP1CON &= 0x0FFFFFFF; // SHIFT_165(P1.7), GP2CON &= 0x0FFFF00F; // CINH_165(P2.7), OE_595(P2.2), STR_595(P2.1)
// Initiatory State CLR_165_SHIFT(); // 74HC165 Pin SET_165_CINH(); CLR_595_OE(); // 74HC595 Pin SET_595_STR();
SET_165_SHIFT_OUT(); // GPIO's Direvtion Set SET_165_CINH_OUT(); SET_595_OE_OUT(); SET_595_STR_OUT();
GP1CON = (GP1CON & 0xF000FFFF) | 0x02220000; // MOSI(P1.6), MISO(P1.5), CLK(P1.4) SPIDIV = 0x1F; // Set SPI clock 40960000/(2×(1+SPIDIV)) // 0x1F = 625KHz }
/********************************************************************************************************* * * 这个是测试用的主程序,每个输入和输出都有LED的所以我是直接看它们有没有发光来确定是否读取/发送成功的 * *********************************************************************************************************/
int main(void) { uint32 temp[100], i;
SysClkInit(); PortInit(); ADCInit(); DACInit(); DIOInit(); DAC_Output(1, 1500); DAC_Output(2, 1700); DOutputWrite(0x0000CCCC); Delay_x_ms(500);
DOutputWrite(0x00003333); Delay_x_ms(500);
DOutputWrite(0x00005555); Delay_x_ms(500);
DOutputWrite(0x0000AAAA); Delay_x_ms(500);
for(i = 0; i < 100; i++) { temp = DInputRead(); }
while(1) { for(i = 0; i < 100; i++) { DOutputWrite(temp); } } } |