SPI调试笔记
root-2011-01-09
实现了通过CPU的SPI控制器来读写外部Flash,做一下笔记。
CPU:LPC2366,内置1个SPI控制器,两个SSP控制器。
Flash:AT45DB321,通过SPI接口读写,13 MHzMax Clock Frequency
CPU设置为SPI master,AT45DB321为Slave,读写时钟都是由master发出的,在读AT45DB321的时候通过写CPU的SPI数据寄存器来产生读时钟。
SPI master初始化代码:
void mSPI_Init(void)
{
U8u8_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); // spicontroller 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)
{
U8u8_dat;
S0SPDR= 0x00; // wrtie dummy byte outto generate clock, then read data from miso
while((S0SPSR & 0x80) == 0); // spicontroller is busy when S0SPSR[7] == 0
u8_dat= S0SPSR;
u8_dat= S0SPDR;
returnu8_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)
{
U8u8_i, u8_dat;
SSP1CR1= 0x00; // disablessp 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 ismaster
for(u8_i = 8; u8_i > 0; u8_i--){
u8_dat= SSP1DR; // clear RxFIFO
}
}
写数据:
void mSPI1_Send(const U8 *u8_buf, U32u32_len)
{
U8u8_dat;
if(u32_len == 0){
return;
}
do{
while( !(SSP1SR & 0x02) );// TxFIFO isfull when SSP1SR[1] is 0
SSP1DR= *u8_buf++;
while(SSP1SR & 0x10); // Wait untilthe Busy bit is cleared
u8_dat = SSP1DR;// flush RxFIFO,一定要读,要不然后面mSPI1_RecByte读回来//的是0xff
}while (u32_len--);
}
读数据:
U8 mSPI1_RecvByte(void)
{
U8u8_dat;
SSP1DR= 0x00; // wrtie dummy byte out togenerate clock, then read data from miso
while(SSP1SR & 0x10); // Wait untilthe Busy bit is cleared
u8_dat= SSP1DR;
returnu8_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)
{
INT8Ui;
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)
{
INT8Ui, 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();
returndat;
}