最近进度有点慢。现在把我SPI这部分分享下吧。这次我使用SPI0和I2C2这两个模块,I2C2负责采集MPU6050的数据,然后用OLED刷新数据。
SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议,在LPC5410中有两个SPI的模块,分别是SPI0和SPI1。
SPI根据SPI时钟极性的极性和SPI时钟相位,SPI时钟极性CPOL, =0表示在没有数据传输时为低电平,= 1表示没有数据传输时为高电平。SPI时钟相位CPHA,= 0表示时钟的第一个沿更新数据、第二个沿锁存数据,= 1表示时钟的第一个沿锁存数据、第二个沿更新数据。如下面的几个时序图:
我这次用了LPC54102的SPI0刷了小OLED。首先LPC54102套件上有个SPI / I2C brdge header,如下套件的原理图:
具体位置如下图:
板子的背面有对应的丝印文字,很容易找到。
这次没用到中断和DMA。首先我们要配置好管脚。
voidInit_SPI_PinMux(void)
{
/* 1.3 = SPI0_SCK, 0.14 = SPI0_SSELN0,0.12 = SPI0_MOSI, 1.4 = SPI0_MISO */
Chip_IOCON_PinMuxSet(LPC_IOCON, 1,3, (IOCON_FUNC5 | IOCON_DIGITAL_EN |IOCON_MODE_PULLUP));
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 14,(IOCON_FUNC1 | IOCON_DIGITAL_EN | IOCON_MODE_PULLUP));
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 12,(IOCON_FUNC1 | IOCON_DIGITAL_EN | IOCON_MODE_PULLUP));
Chip_IOCON_PinMuxSet(LPC_IOCON, 1,4, (IOCON_FUNC5 | IOCON_DIGITAL_EN |IOCON_MODE_PULLUP));
}
然后进行SPI的初始化。如下函数:
根据OLED上的SSD1306提供的手册和别人的写的模拟SPI驱动,我们要选用CPOL = 0,和CPA = 0这种模式。
SSD1306的4线SPI的时序图:
voidSPI_Init()
{
uint32_t memSize, *devMem;
ROM_SPIM_INIT_T spimInit;
ROM_SPIM_XFER_CONFIG_T spimConfig;
int i;
Init_SPI_PinMux();
Chip_Clock_EnablePeriphClock(LPC_SPIM_CLOCK);
Chip_SYSCON_PeriphReset(LPC_SPIM_RESET);
/* Get needed size for drivercontext memory */
memSize = ROM_SPIM_GetMemSize();
if (memSize 》 sizeof(drvData)) {
DEBUGOUT(“Can‘t allocatememory for driver context ”);
}
devMem = drvData; /* Or just use malloc(memSize) */
/* Initialize driver */
spimInit.pUserData = NULL;
spimInit.base = (uint32_t) LPC_SPIM_PORT;
spimInit.baseClockRate =Chip_Clock_GetAsyncSyscon_ClockRate();
spimInit.spiPol[0] = 0; /* Active low select for SSEL0 */
spimInit.spiPol[1] = 1;
spimInit.spiPol[2] = 1;
spimInit.spiPol[3] = 1;
spimHandle = ROM_SPIM_Init(devMem,&spimInit);
if (spimHandle == NULL) {
/* Error initializing SPI */
DEBUGOUT(“Error initializingROM ”);
}
/* Set SPI transfer configuration */
spimConfig.dXferBitRate = SPI_BITRATE;
spimConfig.mode =ROM_SPI_CLOCK_CPHA0_CPOL0;
spimConfig.lsbFirst = 0;
spimConfig.dataBits = 8;
spimConfig.PreDelay = 3;
spimConfig.PostDelay = 1;
spimConfig.FrameDelay = 2;
spimConfig.TransferDelay = 1;
if (ROM_SPIM_SetupTransfer(spimHandle,&spimConfig) != LPC_OK) {
DEBUGOUT(“SPI configurationis invalid ”);
}
/* Show desired and actual SPI rates */
DEBUGOUT(“SPI rate = %d (actual%d) ”, spimConfig.dXferBitRate, spimConfig.rXferBitRate);
/* Callback registration for assertionand de-assertion events */
ROM_SPIM_RegisterCallback(spimHandle,ROM_SPIM_ASSERTSSEL_CB, (void *) CBspiMasterXferCSAssertCB);
ROM_SPIM_RegisterCallback(spimHandle,ROM_SPIM_DEASSERTSSEL_CB, (void *) CBspiMMasterXferCSDeAssertCB);
}
我对这里面几个关键的参数作下说明吧:
spimInit.spiPol[0] = 0; /* Active low select for SSEL0 */
spimInit.spiPol[1] = 1;
spimInit.spiPol[2] = 1;
spimInit.spiPol[3] = 1;
spimInit.spiPol[X]是对应的4个片选SSEL0~ SSEL3引脚。
spimConfig.dXferBitRate= SPI_BITRATE;这个是时钟频率的参数,单位是HZ。
spimConfig.mode= ROM_SPI_CLOCK_CPHA0_CPOL0;这是设定SPI时钟极性的极性和SPI时钟相位的参数。如在SPI的底层中可以看到这4个参数代表了4中模式。
spimConfig.lsbFirst= 0;这个是设置开始传输的数据是最高位还是最低位。9代表开始传输的是最高位,1代表开始传输的最低位。
spimConfig.dataBits= 8;这个参数是每次传输的数据多少位,可以1到16bit数据之间。
spimConfig.PreDelay = 3;
spimConfig.PostDelay = 1;
spimConfig.FrameDelay = 2;
spimConfig.TransferDelay = 1;
上面这几个参数是传输时的几个延时,我这里就不作过多说明了,我也在了解中。