By Toradex胡珊逢
Colibri iMX8X?計算機(jī)模塊上的處理器具有?Cortex-A35?和?Cortex-M4F呻粹。在 ?A35?上運(yùn)行?Linux?操作系統(tǒng),?M4F?通常運(yùn)行一個實時擦操作系統(tǒng)例如?FreeRTOS决左。NXP?的MCUxpresso SDK?提供了Cortex-M4F?例程,能夠幫助用戶進(jìn)行開發(fā)浪册。但在MCUxpresso SDK?中只提供了少量的外設(shè)操作演示,本文將介紹如何修改配置文件缴川,并調(diào)用FreeRTOS API?創(chuàng)建一個SPI?例程厕诡,驅(qū)動SPI?接口的OLED?屏幕党远。
首先從NXP?網(wǎng)站下載?MCUxpresso SDK削解。根據(jù)所使用的模塊,分別選擇Select Development Board → Processors → I.MX → 8QuadXPlus → MIMX8QXx → MIMX8QX5xxxDZ/MIMX8QX6xxxDZ沟娱,最后點擊Build MCUXpresso SDK?即可下載氛驮。
在SDK?安裝目錄的boards/mekmimx8qx/rtos_examples/?位置創(chuàng)建一個freertos_lpspi?文件夾,里面工程文件可以從freertos_lpuart?復(fù)制然后進(jìn)行修改济似,我們也提供修改好的例程以便使用矫废。主要修改的內(nèi)容如下盏缤。
l?pin_mux.h
定義使用的引腳,包括輸出調(diào)試信息的串口磷脯,LPSPI?以及兩個?GPIO?用于?OLED?的復(fù)位和命令/數(shù)據(jù)選擇蛾找。
---------------------------------------
/* ADC_IN2 (coord V32), M40_UART0_RX */
#define BOARD_INITPINS_M40_UART0_RX_PIN_FUNCTION_ID SC_P_SCU_GPIO0_00 /*!< Pin function id */
/* ADC_IN3 (coord V30), M40_UART0_TX */
#define BOARD_INITPINS_M40_UART0_TX_PIN_FUNCTION_ID SC_P_SCU_GPIO0_01 /*!< Pin function id */
#define BOARD_INITPINS_SPI2_MOSI_PIN_FUNCTION_ID SC_P_SPI2_SDO
#define BOARD_INITPINS_SPI2_MISO_PIN_FUNCTION_ID SC_P_SPI2_SDI
#define BOARD_INITPINS_SPI2_CLK_PIN_FUNCTION_ID SC_P_SPI2_SCK
#define BOARD_INITPINS_SPI2_CS0_PIN_FUNCTION_ID SC_P_SPI2_CS0
#define BOARD_INITPINS_BB_UART2_TX_PIN_FUNCTION_ID SC_P_UART2_TX /* SODIMM21 GPIO1.IO23 OLED COMMAND/DATA SELECT*/
#define BOARD_INITPINS_BB_UART2_RX_PIN_FUNCTION_ID SC_P_UART2_RX /* SODIMM19 GPIO1.IO24 OLED RESET*/
---------------------------------------
l?pin_mux.c
初始化上面定義的引腳娩脾,并配置復(fù)用關(guān)系赵誓。設(shè)置在BOARD_InitPins函數(shù)中完成。
---------------------------------------
void BOARD_InitPins(sc_ipc_t ipc) /*!< Function assigned for the core: Cortex-M4F[m4] */
{
sc_err_t err = SC_ERR_NONE;
err = sc_pad_set_all(ipc, BOARD_INITPINS_M40_UART0_RX_PIN_FUNCTION_ID, 2U, SC_PAD_CONFIG_NORMAL, ????SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);/* IOMUXD_ADC_IN2 register modification value */
if (SC_ERR_NONE != err)
{
assert(false);
}
---------------------------------------
l?freertos_lpspi.c
這里包括了對LPSPI?的設(shè)置柿赊,以及通過?SPI?發(fā)送數(shù)據(jù)俩功。
---------------------------------------
sc_pm_set_resource_power_mode(ipc, SC_R_SPI_2, SC_PM_PW_MODE_ON)
---------------------------------------
配置?LPSPI?的供電。
---------------------------------------
sc_pm_clock_enable(ipc, SC_R_SPI_2, SC_PM_CLK_PER, true, 0);if (CLOCK_SetIpFreq(kCLOCK_DMA_Lpspi2, SC_60MHZ) == 0)
---------------------------------------
設(shè)置?LPSPI?時鐘源碰声。
---------------------------------------
LPSPI_RTOS_Init(&handle, ADMA__LPSPI2, &lpspi_config, LPUART_CLK_FREQ)
---------------------------------------
完成對?LPSPI?工作狀態(tài)配置诡蜓,包括?SPI?時鐘頻率、相位胰挑、采樣點蔓罚、幀長等,這些包含在?lpspi_config?結(jié)構(gòu)體中瞻颂。
---------------------------------------
lpspi_master_config_t lpspi_config = {.baudRate = 6000000,.bitsPerFrame = 1024, /*!< Bits per frame, minimum 8, maximum 4096.*/.cpol = kLPSPI_ClockPolarityActiveLow,.cpha = kLPSPI_ClockPhaseSecondEdge,.direction = kLPSPI_MsbFirst,.pcsToSckDelayInNanoSec = 50,.lastSckToPcsDelayInNanoSec = 50,.betweenTransferDelayInNanoSec = 50,.whichPcs = kLPSPI_Pcs0,.pcsActiveHighOrLow = kLPSPI_PcsActiveLow,.pinCfg = kLPSPI_SdiInSdoOut,.dataOutConfig = kLpspiDataOutRetained,};
---------------------------------------
其中bitsPerFrame?是指?SPI?的幀長豺谈,根據(jù)?SPI?設(shè)備實際數(shù)據(jù)輸入要求需要做相應(yīng)的更改,通常指令和數(shù)據(jù)的長度是不一樣贡这。例如在這個例程里多次調(diào)用?LPSPI_RTOS_Init?函數(shù)對其進(jìn)行調(diào)整茬末。
---------------------------------------
LPSPI_RTOS_TransferBlocking(&handle, &spi_data)
---------------------------------------
該函數(shù)實現(xiàn)?SPI?數(shù)據(jù)發(fā)送。由于采用了阻塞的方式發(fā)送盖矫,需要等待數(shù)據(jù)傳輸完畢才推出函數(shù)丽惭。數(shù)據(jù)存儲在?lpspi_transfer_t ?格式的結(jié)構(gòu)體中。其中也包含了?SPI?一些配置辈双,例如使用哪個?CS?片選责掏,是否連續(xù)發(fā)送等。
---------------------------------------
lpspi_transfer_t spi_data = {
.txData = send_buffer,
.rxData = recv_buffer,
.dataSize = sizeof(send_buffer),
.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap,
};
---------------------------------------
上面SPI?相關(guān)API?主要來自devices/MIMX8QX6/drivers/fsl_lpspi_freertos.c湃望,fsl_lpspi.c拷橘。在默認(rèn)的fsl_lpspi_freertos.c?中只有非阻塞方式的SPI?傳輸函數(shù)?LPSPI_RTOS_Transfer()。因此在這里我們新構(gòu)建一個阻塞方式的函數(shù)?LPSPI_RTOS_TransferBlocking()喜爷。
---------------------------------------
status_t LPSPI_RTOS_TransferBlocking(lpspi_rtos_handle_t *handle, lpspi_transfer_t *transfer){??status_t status;??status = LPSPI_MasterTransferBlocking(handle->base, transfer);??if (status != kStatus_Success)??{????return status;??}??return status;}
---------------------------------------
在?fsl_lpspi_freertos.h?頭文件中申明該函數(shù)冗疮。
---------------------------------------
status_t LPSPI_RTOS_TransferBlocking(lpspi_rtos_handle_t *handle, lpspi_transfer_t *transfer);
---------------------------------------
另外為了支持編譯,在?devices/MIMX8QX6/drivers?目錄中創(chuàng)建?driver_lpspi_freertos_MIMX8QX6.cmake和?driver_lpspi_MIMX8QX6.cmake兩個文件檩帐。相應(yīng)地在上面項目工程目錄中的boards/mekmimx8qx/rtos_examples/freertos_lpspi/armgcc/CMakeLists.txt?中將?LPSPI?的驅(qū)動添加進(jìn)來术幔。
---------------------------------------
# include modulesinclude(driver_clock_MIMX8QX6)include(driver_lpspi_MIMX8QX6)include(driver_lpspi_freertos_MIMX8QX6)
---------------------------------------
到此我們已經(jīng)完成?LPSPI?在?FreeRTOS?的配置以及創(chuàng)建一個工程項目來使用?LPSPI?發(fā)送數(shù)據(jù)。上面的操作涉及SDK?中多處修改湃密,為了方便用戶測試诅挑,我們也提供經(jīng)修改的整個SDK四敞。
編譯好后,在?U-Boot?中通過?tftp?下載?M4?固件并運(yùn)行拔妥。
---------------------------------------
Colibri iMX8X # ??print m4boot_test
m4boot_test=tftp ${loadaddr} m4_0.bin; dcache flush; bootaux ${loadaddr} 0Colibri iMX8X # run m4boot_test
---------------------------------------
OLED?屏幕顯示如下忿危。
總結(jié)
通過上面的內(nèi)容介紹了如何在?M4?上使用默認(rèn)例程之外的外設(shè),SDK?中還提供了諸多外設(shè)的?FreeRTOS API没龙。用戶可以使用類似的方法進(jìn)行開發(fā)铺厨。