最近進度有點慢。現在把我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;
上面這幾個參數是傳輸時的幾個延時,我這里就不作過多說明了,我也在了解中。
附上測試圖:
線接的有些亂;
現在共享我的源代碼:
里面集成ADXL345和MPU6050的驅動,看過時序,沒問題。
評論
查看更多