SPI调试笔记
root-2011-01-09
实现了通过CPU的SPI控制器来读写外部Flash,做一下笔记。
CPU:LPC2366,内置1个SPI控制器,两个SSP控制器。
Flash:AT45DB321,通过SPI接口读写,13 MHz Max Clock Frequency
CPU设置为SPI master,AT45DB321为Slave,读写时钟都是由master发出的,在读AT45DB321的时候通过写CPU 的SPI数据寄存器来产生读时钟。
SPI master初始化代码:
void mSPI_Init(void)
{
U8 u8_dummy;
PINSEL0 &= ~(3U << 30);
PINSEL0 |= 3U << 30; // P0[15], SCK
PINSEL1 &= ~0xffU; // P0[16-19], SSEL, MISO, MOSI, WP
PINSEL1 |= 0x3c;
PIN_SET(P0, PIN_AT45_WP | PIN_AT45_CS);
PIN_DIR(P0, PIN_AT45_WP | PIN_AT45_CS, OUT);
S0SPCCR = 0x52; // 分频时钟
S0SPCR = (0 << 2) | // bitEnable, 8bit
(0 << 3) | // cpha
(0 << 4) | // cpol
(1 << 5) | // mstr = 1, 主模式
(0 << 6) | // lsbf = 0, msb位在先
(0 << 7); // 禁止spi中断
u8_dummy = S0SPSR; // flush SPI Rx buffer
u8_dummy = S0SPDR;
u8_dummy = S0SPSR;
u8_dummy = S0SPDR;
}
SPI master发送1byte数据:
static void mSPI_SendByte(U8 u8_dat)
{
S0SPDR = u8_dat;
while ((S0SPSR & 0x80) == 0); // spi controller is busy when S0SPSR[7] == 0
u8_dat = S0SPSR;
u8_dat = S0SPDR; // flush the Rx buffer,这个一定要读,否则后面调用读函//数的时候读出来的是0xff
}
SPI master接收1byte数据:
static U8 mSPI_RecvByte(void)
{
U8 u8_dat;
S0SPDR = 0x00; // wrtie dummy byte out to generate clock, then read data from miso
while ((S0SPSR & 0x80) == 0); // spi controller is busy when S0SPSR[7] == 0
u8_dat = S0SPSR;
u8_dat = S0SPDR;
return u8_dat;
}
读AT45DB321状态寄存器的例子:
mSPI1_Init();
PIN_CLR(P0, PIN_AT45_CS);
mSPI_SendByte(0xd7);
u8_tmp = mSPI_RecvByte();
PIN_SET(P0, PIN_AT45_CS);
通过LPC2366的SSP1读写AT45DB321的代码
void mSPI1_Init(void)
{
U8 u8_i, u8_dat;
SSP1CR1 = 0x00; // disable ssp controller before configuration
PINSEL0 &= ~(0x3ff << 10);
PINSEL0 |= 0x2a0 << 10;
PIN_DIR(P0, PIN_AT45_WP | PIN_AT45_CS, OUT);
PIN_SET(P0, PIN_AT45_WP | PIN_AT45_CS);
SSP1CR0 = (7 << 0) | // 8bit
(0 << 4) | // ssp is configured to spi
(0 << 6) | // cpol
(0 << 7) | // cpha
(0x07 << 8); // scr
SSP1CPSR = 0x30;
SSP1CR1 = (0 << 0) | // noraml operation
(1 << 1) | // ssp enable
(0 << 2); // spi is master
for (u8_i = 8; u8_i > 0; u8_i--){
u8_dat = SSP1DR; // clear RxFIFO
}
}
写数据:
void mSPI1_Send(const U8 *u8_buf, U32 u32_len)
{
U8 u8_dat;
if (u32_len == 0){
return;
}
do {
while ( !(SSP1SR & 0x02) ); // TxFIFO is full when SSP1SR[1] is 0
SSP1DR = *u8_buf++;
while (SSP1SR & 0x10); // Wait until the Busy bit is cleared
u8_dat = SSP1DR; // flush RxFIFO, 一定要读,要不然后面mSPI1_RecByte读回来//的是0xff
} while (u32_len--);
}
读数据:
U8 mSPI1_RecvByte(void)
{
U8 u8_dat;
SSP1DR = 0x00; // wrtie dummy byte out to generate clock, then read data from miso
while (SSP1SR & 0x10); // Wait until the Busy bit is cleared
u8_dat = SSP1DR;
return u8_dat;
}
读AT45DB321状态寄存器的例子
mSPI1_Init();
PIN_CLR(P0, PIN_AT45_CS);
buf_w[0] = 0xd7;
mSPI1_Send(buf_w, 1);
buf_r[0] = mSPI1_RecvByte();
PIN_SET(P0, PIN_AT45_CS);
通过普GPIO仿SPI时序读写AT45DB321:
/*====================================================================
** 函数名称 : SPI_Wr
** 输入参数 : dat :1字节数据
** 输出参数 : 无
** 影响变量 : 无
** 函数描述 : 写1字节到SPI总线
** 修改描述 : root 2010-10-24
====================================================================*/
static void SPI_Wr(INT8U dat)
{
INT8U i;
OS_ENTER_CRITICAL();
for (i = 0;i<8;i++){
if ((dat & 0x80)==0x80){
PIN_SET(P0, PIN_AT45_SI);
}
else{
PIN_CLR(P0, PIN_AT45_SI);
}
PIN_SET(P0, PIN_AT45_SCK);
PIN_CLR(P0, PIN_AT45_SCK);
dat <<= 1;
}
OS_EXIT_CRITICAL();
}
/*====================================================================
** 函数名称 : SPI_Rd
** 输入参数 : 无
** 输出参数 : dat :1字节数据
** 影响变量 : 无
** 函数描述 : 写1字节到SPI总线
** 修改描述 : root 2010-10-24
====================================================================*/
static INT8U SPI_Rd(void)
{
INT8U i, dat;
OS_ENTER_CRITICAL();
for (dat = 0, i = 0;i<8;i++){
PIN_SET(P0, PIN_AT45_SCK);
dat <<= 1;
if (PIN_GET(P0, PIN_AT45_SO)){
dat |= 1;
}
PIN_CLR(P0, PIN_AT45_SCK);
}
OS_EXIT_CRITICAL();
return dat;
}