ghoulich 发表于 2011-12-26 15:17:04

裸机下的SPI通讯终于搞定了,datasheet就是在胡说八道啊!!

发现数据手册不能信啊。。。说是SPI初始化的时候要发10个0xFF,还有在接收的时候也得同时发0xFF,这简直是误导人啊!!刚刚发现只要把这两个地方的代码删掉,就可以正常通信了,我的程序中以SPI_0为主设备,SPI_1为从设备:


#include "2440addr.h"
#include "2440lib.h"

/* SPI_0 */
#define MISO0 11 /* GPE11:SPI输入*/
#define GET_MISO0() ((rGPEDAT & (1<<MISO0)) >> MISO0)
#define MOSI0 12 /* GPE12:SPI输出*/
#define SET_MOSI0(value) (rGPEDAT = (rGPEDAT & ~(1<<MOSI0)) | (value<<MOSI0))
#define SCK013 /* GPE13:SPI输出*/
#define SET_SCK0(value) (rGPEDAT = (rGPEDAT & ~(1<<SCK0)) | (value<<SCK0))
#define CE0   14 /* GPG14:数字输出 */
#define SET_CE0(value) (rGPGDAT = (rGPGDAT & ~(1<<CE0)) | (value<<CE0))
#define GET_CE0() ((rGPGDAT & (1<<CE0)) >> CE0)
#define CSN02/* GPG2: SPI输出*/
#define SET_CSN0(value) (rGPGDAT = (rGPGDAT & ~(1<<CSN0)) | (value<<CSN0))
#define IRQ013 /* GPG13: 中断输入 */
#define GET_IRQ0() ((rGPFDAT & (1<<IRQ0)) >> IRQ0)

/* SPI_1 */
#define MISO1 5/* GPG5:SPI输入*/
#define GET_MISO1() ((rGPGDAT & (1<<MISO1)) >> MISO1)
#define MOSI1 6/* GPG6:SPI输出*/
#define SET_MOSI1(value) (rGPGDAT = (rGPGDAT & ~(1<<MOSI1)) | (value<<MOSI1))
#define SCK17/* GPG7:SPI输出*/
#define SET_SCK1(value) (rGPGDAT = (rGPGDAT & ~(1<<SCK1)) | (value<<SCK1))
#define CE1   0/* GPG0:数字输出 */
#define SET_CE1(value) (rGPGDAT = (rGPGDAT & ~(1<<CE1)) | (value<<CE1))
#define GET_CE1() ((rGPGDAT & (1<<CE1)) >> CE1)
#define CSN13/* GPG3: SPI输出*/
#define SET_CSN1(value) (rGPGDAT = (rGPGDAT & ~(1<<CSN1)) | (value<<CSN1))
#define IRQ111 /* GPG11: 中断输入 */
#define GET_IRQ1() ((rGPGDAT & (1<<IRQ1)) >> IRQ1)

static void usDelay(U32 uSeconds, void __irq (*PwmIsr)(void)) {
    // set ISR for PWM Timer 4
    if (PwmIsr != NULL) {
      ClearPending(BIT_TIMER4);
      pISR_TIMER4 = (U32) PwmIsr;
      EnableIrq(BIT_TIMER4);
    }

    // timer input clock frequency = PCLK / (24 + 1) / 2 = 1 MHz
        rTCFG0 &= ~(0xff << 8);   // clear TCFG0(Prescaler 1) to 0
        rTCFG0 |= 24 << 8;                  // Prescaler 1 = 24
        rTCFG1 &= ~(0xf << 16);   // clear TCFG1(MUX 4) to 0
        rTCFG1 |= 0 << 16;                  // MUX 4 = 0000 = 1/2

        rTCNTB4 = uSeconds;       // use PWM Timer 4, the initial count value is uSeconds
        rTCON &= ~(0x7 << 20);    // clear TCON to 0
        rTCON |= 0x0 << 22;                  // one-shot
        rTCON |= 0x1 << 21;       // manula update TCNTB4
        rTCON |= 0x1 << 20;       // start for Timer 4
        rTCON &= ~(0x1 << 21);          // clear TCON(Timer 4 Manual Update) to zero
       
        while(rTCNTO4)
          ;
}

static void InitSpi(void) {
   
    // 设置时钟控制寄存器(CLKCON),使能SPI时钟
    rCLKCON = (rCLKCON & ~(1 << 18)) | (1 << 18);
   
    // SPI0为主设备
    // 初始化GPE GPE11:MISO0(MISO);GPE12:MOSI0(MOSI);GPE13:SPICLK0(SCK)
    rGPECON = (rGPECON & ~(3 << MISO0 * 2 | 3 << MOSI0 * 2 | 3 << SCK0 * 2)) |
      (2 << MISO0 * 2 | 2 << MOSI0 * 2 | 2 << SCK0 * 2);
    // 初始化GPG GPG13:GPG2: nSS_SPI0(CSN)
    rGPGCON = (rGPGCON & ~(3 << CSN0 * 2)) | (1 << CSN0 * 2);
    // 设置波特率预定标器寄存器(SPPREn),波特率 = PCLK / 2 / (预定标器值 + 1) = 1MHz
    rSPPRE0 = 0x18;
    // 设置SPCONn寄存器以正确配置SPI模块
    // normal; format A; active high; master; enable; polling mode
    rSPCON0 = (rSPCON0 & ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 3 << 5)) |
      (0 << 0 | 0 << 1 | 0 << 2 | 1 << 3 | 1 << 4 | 0 << 5);
    // 设置SPI引脚控制寄存器(SPPINn)
    // Release; Disable (general purpose)
    rSPPIN0 = (rSPPIN0 & ~(1 << 0 | 1 << 2)) | (0 << 0 | 0 << 2);
   
    // SPI1为从设备
    // 初始化GPG GPG5:MISO1(MISO);GPG6:MOSI1(MOSI);GPG7:SPICLK1(SCK)
    //         GPG3: nSS_SPI1(CSN)
    rGPGCON = (rGPGCON & ~(3 << MISO1 * 2 | 3 << CSN1 * 2 | 3 << MOSI1 * 2 | 3 << SCK1 * 2)) |
      (3 << MISO1 * 2 | 3 << CSN1 * 2 | 3 << MOSI1 * 2 | 3 << SCK1 * 2);
    // 设置波特率预定标器寄存器(SPPREn),波特率 = PCLK / 2 / (预定标器值 + 1) = 1MHz
    rSPPRE1 = 0x18;
    // 设置SPCONn寄存器以正确配置SPI模块
    // normal; format A; active high; master; enable; polling mode
    rSPCON1 = (rSPCON1 & ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 3 << 5)) |
      (0 << 0 | 0 << 1 | 0 << 2 | 0 << 3 | 0 << 4 | 0 << 5);
    // 设置SPI引脚控制寄存器(SPPINn)
    // Release; Disable (general purpose)
    rSPPIN1 = (rSPPIN1 & ~(1 << 0 | 1 << 2)) | (0 << 0 | 0 << 2);
}

static void Spi0Send(char uch) {
    char temp;

        // 将nSS(CSN)引脚设为低电平,激活SPI模块
    SET_CSN0(0);
    usDelay(1, NULL);
                
    rSPTDAT0 = uch;
    // 判定SPSTAn寄存器的REDY标志
    while (!(rSPSTA0 & 0x01))
      ;
                
        // 将nSS(CSN)引脚设为高电平,关闭SPI模块
        SET_CSN0(1);
        usDelay(1, NULL);
}

static char Spi1Receive(void) {
    char temp;

    // 判定SPSTAn寄存器的REDY标志
    while (!(rSPSTA1 & 0x01))
      ;
    temp = rSPRDAT1;
       
        return temp;
}

void SpiTest(void) {
    int value = 0xDE;

    InitSpi();
    Uart_Printf("\nSPI_0 Sent 0x%X\n", value);
    Spi0Send(value);
    Uart_Printf("\nSPI_1 Recieved 0x%X\n", Spi1Receive());
}

embedsky_lhh 发表于 2011-12-27 08:59:49

初始化的时候要发10个0xFF,那个是初始化MMC和SD卡时的吧!

ghoulich 发表于 2011-12-27 09:37:59

有可能吧,SPI使用的通用用法datasheet上也没写,只好照它写的示例做,结果杯具了

eliefly 发表于 2013-9-11 11:34:53

这个移位控制搞得真麻烦

向前翻滚 发表于 2013-10-18 10:09:46

数据手册确实不能全信了!
页: [1]
查看完整版本: 裸机下的SPI通讯终于搞定了,datasheet就是在胡说八道啊!!