LPC2138微控制器之SPI

LPC2138微控制器有2个SPI接口,其中SPI 1兼容SSP接口。

关于SPI协议,可以参考我的上一篇博文《SPI协议详解》。

SPI总线全双工通信体现在发送数据的同时也在接收数据,主要是在SCLK时钟的控制下,通过两个双向移位寄存器进行数据交换。

寄存器描述

S0SPCCR和S0SPCR寄存器在数据传输之前设置,主要是配置SPI工作模式、时钟频率和中断。

S0SPSR寄存器保存SPI控制器状态,只读。其中SPIF位表示数据传输完成,其他位表示异常状态。

S0SPDR寄存器负责数据传输

1)写数据

SPI控制器内部有一个移位寄存器负责数据发送和接收,往S0SPDR寄存器写数据会马上写入移位寄存器,因此在SPIF没有置位时(即数据传输过程中),不应该往S0SPDR中写入数据。

另外,往S0SPDR写数据,才会产生SCLK时钟周期,其他情况下,SCLK保持高电平或者低电平。

2)读数据

SPI控制器接收数据会缓存到一个单独的数据缓存寄存器中,读S0SPDR寄存器实际上返回该寄存器值。如果在接收到下一个字节数据之前,没有及时读取该寄存器,则下一个字节会直接丢弃,而不是覆写到该寄存器中。

实例

本来想用Proteus模拟SPI读写MMC卡,但是折腾了两天,MMC卡初始化都不成功,CMD0切换到idle模式一直不返回0x1。所以直接用MISO和MOSI自环测试了SPI读写。

#include <lpc213x.h>
#include "spi.h"
#include "serial.h"

#define SPI_DEBUG (1)

#if 0
void spi0_isr(void) __irq
{
    unsigned char status;
    unsigned char recv_byte;

    if ((VICIRQStatus & 0x400) && (S0SPINT & 0x1))
    {
        /* Interrupt Occurs */
        status = S0SPSR;

        if (status & 0x78)
        {
            /* ABRT/MODF/ROVR/WCOL exceptions */
            sendstr("spi bus 0 exception, status=");
            sendhex(status);
            sendstr("
");
        }
        else if (status == 0x80)
        {
            /* SPIF indicates SPI Transfer Completed,
            ** read or write SPI Data Reg clear SPIF
            */
            recv_byte = S0SPDR;
            sendstr("spi bus 0 recv ");
            sendhex(recv_byte);
            sendstr("
");
        }

        /* Clear Interrupt */
        S0SPINT = 0x1;
    }

}
#endif

void spi_init(void)
{
    /* Configure P0.4~7 as SPI bus 0 */
    PINSEL0 &= ~0x0000FF00;
    PINSEL0 |= 0x00005500;

    /* PCLK is 30MHz, SPI Clock Frequency is 5MHz */
    S0SPCCR = 0x6;

    /* Master mode, 8 bits per transfer(MSB first),
    ** disable interrupt, CPOL=0, CPHA=0
    */
    S0SPCR = 0x20;

#if 0
    /* SPI Bus 0 ISR */
    VICVectCntl2 = 0x20 | 10;
    VICVectAddr2 = (unsigned int)spi0_isr;
    VICIntEnable = 1 << 10;
#endif

}

int spi_write_byte(unsigned char byte)
{
    unsigned char recv_byte;

    if (SPI_DEBUG)
    {
        sendstr("spi bus 0 send ");
        sendhex(byte);
        sendstr("
");
    }

    S0SPDR = byte;

    /* Check SPIF bit, Wait for Data Transfer Complete */
    while (!(S0SPSR & 0x80));
    recv_byte = S0SPDR;
    if (SPI_DEBUG)
    {
        sendstr("spi bus 0 recv ");
        sendhex(recv_byte);
        sendstr("
");
    }

    return recv_byte;
}

int spi_read_byte(unsigned char *byte)
{
    if (0 == byte)
    {
        sendstr("spi_read_byte byte is NULL
");
        return -1;
    }

    /* Only Write S0SPDR generate SPI Clock for receive data */
    *byte = spi_write_byte(0xFF);

    return 0;
}

int spi_write(unsigned char *data, int len)
{
    int i = 0;

    if (0 == data)
    {
        sendstr("spi_write data is NULL
");
        return -1;
    }

    for (i = 0; i < len; i++)
    {
        spi_write_byte(data[i]);
    }

    return 0;
}

int spi_read(unsigned char *data, int len)
{
    int i = 0;

    if (0 == data)
    {
        sendstr("spi_read data is NULL
");
        return -1;
    }

    for (i = 0; i < len; i++)
    {
        spi_read_byte(&data[len - 1 -i]);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/justin-y-lin/p/12349235.html