最近進(jìn)度有點(diǎn)慢。現(xiàn)在把我SPI這部分分享下吧。這次我使用SPI0和I2C2這兩個(gè)模塊,I2C2負(fù)責(zé)采集MPU6050的數(shù)據(jù),然后用OLED刷新數(shù)據(jù)。
SPI是串行外設(shè)接口(Serial Peripheral Interface)的縮寫。SPI,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節(jié)約了芯片的管腳,同時(shí)為PCB的布局上節(jié)省空間,提供方便,正是出于這種簡單易用的特性,如今越來越多的芯片集成了這種通信協(xié)議,在LPC5410中有兩個(gè)SPI的模塊,分別是SPI0和SPI1。
SPI根據(jù)SPI時(shí)鐘極性的極性和SPI時(shí)鐘相位,SPI時(shí)鐘極性CPOL, =0表示在沒有數(shù)據(jù)傳輸時(shí)為低電平,= 1表示沒有數(shù)據(jù)傳輸時(shí)為高電平。SPI時(shí)鐘相位CPHA,= 0表示時(shí)鐘的第一個(gè)沿更新數(shù)據(jù)、第二個(gè)沿鎖存數(shù)據(jù),= 1表示時(shí)鐘的第一個(gè)沿鎖存數(shù)據(jù)、第二個(gè)沿更新數(shù)據(jù)。如下面的幾個(gè)時(shí)序圖:
我這次用了LPC54102的SPI0刷了小OLED。首先LPC54102套件上有個(gè)SPI / I2C brdge header,如下套件的原理圖:
具體位置如下圖:
板子的背面有對(duì)應(yīng)的絲印文字,很容易找到。
這次沒用到中斷和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));
}
然后進(jìn)行SPI的初始化。如下函數(shù):
根據(jù)OLED上的SSD1306提供的手冊(cè)和別人的寫的模擬SPI驅(qū)動(dòng),我們要選用CPOL = 0,和CPA = 0這種模式。
SSD1306的4線SPI的時(shí)序圖:
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);
}
我對(duì)這里面幾個(gè)關(guān)鍵的參數(shù)作下說明吧:
spimInit.spiPol[0] = 0; /* Active low select for SSEL0 */
spimInit.spiPol[1] = 1;
spimInit.spiPol[2] = 1;
spimInit.spiPol[3] = 1;
spimInit.spiPol[X]是對(duì)應(yīng)的4個(gè)片選SSEL0~ SSEL3引腳。
spimConfig.dXferBitRate= SPI_BITRATE;這個(gè)是時(shí)鐘頻率的參數(shù),單位是HZ。
spimConfig.mode= ROM_SPI_CLOCK_CPHA0_CPOL0;這是設(shè)定SPI時(shí)鐘極性的極性和SPI時(shí)鐘相位的參數(shù)。如在SPI的底層中可以看到這4個(gè)參數(shù)代表了4中模式。
spimConfig.lsbFirst= 0;這個(gè)是設(shè)置開始傳輸?shù)臄?shù)據(jù)是最高位還是最低位。9代表開始傳輸?shù)氖亲罡呶唬?代表開始傳輸?shù)淖畹臀弧?/p>
spimConfig.dataBits= 8;這個(gè)參數(shù)是每次傳輸?shù)臄?shù)據(jù)多少位,可以1到16bit數(shù)據(jù)之間。
spimConfig.PreDelay = 3;
spimConfig.PostDelay = 1;
spimConfig.FrameDelay = 2;
spimConfig.TransferDelay = 1;
上面這幾個(gè)參數(shù)是傳輸時(shí)的幾個(gè)延時(shí),我這里就不作過多說明了,我也在了解中。
附上測(cè)試圖:
線接的有些亂;
現(xiàn)在共享我的源代碼:
里面集成ADXL345和MPU6050的驅(qū)動(dòng),看過時(shí)序,沒問題。
評(píng)論
查看更多