教你LPC54102双核套件固件库SPI的用法

2023-04-03  

  最近进度有点慢。现在把我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双核套件固件库SPI的用法

  教你LPC54102双核套件固件库SPI的用法

  教你LPC54102双核套件固件库SPI的用法

  教你LPC54102双核套件固件库SPI的用法

  教你LPC54102双核套件固件库SPI的用法

  我这次用了LPC54102的SPI0刷了小OLED。首先LPC54102套件上有个SPI / I2C brdge header,如下套件的原理图:

  教你LPC54102双核套件固件库SPI的用法

  具体位置如下图:

  教你LPC54102双核套件固件库SPI的用法

  板子的背面有对应的丝印文字,很容易找到。

  这次没用到中断和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的时序图:

  教你LPC54102双核套件固件库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中模式。

  教你LPC54102双核套件固件库SPI的用法

  spimConfig.lsbFirst= 0;这个是设置开始传输的数据是最高位还是最低位。9代表开始传输的是最高位,1代表开始传输的最低位。

  spimConfig.dataBits= 8;这个参数是每次传输的数据多少位,可以1到16bit数据之间。

  spimConfig.PreDelay = 3;

  spimConfig.PostDelay = 1;

  spimConfig.FrameDelay = 2;

  spimConfig.TransferDelay = 1;

  上面这几个参数是传输时的几个延时,我这里就不作过多说明了,我也在了解中。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。