IMX8QXP Cortex-M4 SPI测试

        IMX8QXP Cortex-M4 SPI主从模式测试,利用内部的单片机M4核接收SPI数据进行测试。

环境准备

        下载NXP MCU SDK,下载编译链,参考韬睿文章NXP iMX8X M4核心SPI开发,使用IMX8QXP demo板,M4核spi3做主模式,A35核spi0做从模式,飞线连接:

 M4代码修改

        直接在freertos_hello测试代码中修改。

        修改编译配置文件:

        devices/MIMX8QX6/drivers/driver_lpspi_freertos_MIMX8QX6.cmake

if(NOT DRIVER_LPUSPI_FREERTOS_MIMX8QX6_INCLUDED)
    
    set(DRIVER_LPSPI_FREERTOS_MIMX8QX6_INCLUDED true CACHE BOOL "driver_lpspi_freertos component is included.")

    target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}/fsl_lpspi_freertos.c
    )


    target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}/.
    )


    include(driver_lpspi_MIMX8QX6)

    include(middleware_freertos-kernel_MIMX8QX6)

endif()

        devices/MIMX8QX6/drivers/driver_lpspi_MIMX8QX6.cmake

if(NOT DRIVER_LPSPI_MIMX8QX6_INCLUDED)
    
    set(DRIVER_LPSPI_MIMX8QX6_INCLUDED true CACHE BOOL "driver_lpspi component is included.")

    target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}/fsl_lpspi.c
    )


    target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}/.
    )


    include(driver_common_MIMX8QX6)

endif()

        boards/mekmimx8qx/rtos_examples/freertos_hello/armgcc/CMakeLists.txt

include(driver_lpspi_MIMX8QX6)

include(driver_lpspi_freertos_MIMX8QX6)

        修改代码文件:

        pin_mux.h

/* ADC_IN2 (coord V32), M40_UART0_RX */
#define BOARD_INITPINS_M40_UART0_RX_PIN_FUNCTION_ID                 SC_P_ADC_IN2   /*!< Pin function id */

/* ADC_IN3 (coord V30), M40_UART0_TX */
#define BOARD_INITPINS_M40_UART0_TX_PIN_FUNCTION_ID                 SC_P_ADC_IN3   /*!< Pin function id */

#define BOARD_INITPINS_SPI3_MOSI_PIN_FUNCTION_ID                 	SC_P_SPI3_SDO
#define BOARD_INITPINS_SPI3_MISO_PIN_FUNCTION_ID                 	SC_P_SPI3_SDI
#define BOARD_INITPINS_SPI3_CLK_PIN_FUNCTION_ID                  	SC_P_SPI3_SCK
#define BOARD_INITPINS_SPI3_CS0_PIN_FUNCTION_ID                  	SC_P_SPI3_CS0

        pin_mux.c

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, 1U, 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);
  }
  err = sc_pad_set_all(ipc, BOARD_INITPINS_M40_UART0_TX_PIN_FUNCTION_ID, 1U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);/* IOMUXD_ADC_IN3 register modification value */
  if (SC_ERR_NONE != err)
  {
      assert(false);
  }

  err = sc_pad_set_all(ipc, BOARD_INITPINS_SPI3_MOSI_PIN_FUNCTION_ID, 0U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);
  if (SC_ERR_NONE != err)
  {
      assert(false);
  }
  err = sc_pad_set_all(ipc, BOARD_INITPINS_SPI3_MISO_PIN_FUNCTION_ID, 0U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);
  if (SC_ERR_NONE != err)
  {
      assert(false);
  }
  err = sc_pad_set_all(ipc, BOARD_INITPINS_SPI3_CLK_PIN_FUNCTION_ID, 0U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);
  if (SC_ERR_NONE != err)
  {
      assert(false);
  }
  err = sc_pad_set_all(ipc, BOARD_INITPINS_SPI3_CS0_PIN_FUNCTION_ID, 0U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);
  if (SC_ERR_NONE != err)
  {
      assert(false);
  }
}

        freertos_hello.c

/*
 * Copyright (c) 2015, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/* FreeRTOS kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"

/* Freescale includes. */
#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"

#include "fsl_lpuart.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/

#include "fsl_lpspi_freertos.h"
lpspi_rtos_handle_t handle;
lpspi_master_config_t masterConfig;
#define LPUART_CLK_FREQ   CLOCK_GetIpFreq(kCLOCK_DMA_Lpspi3)
uint8_t send_buffer[128];
uint8_t recv_buffer[128];
lpspi_transfer_t spi_data = {
    .txData = send_buffer,
    .rxData = recv_buffer,
    .dataSize = sizeof(send_buffer),
    .configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap,
};

/* Task priorities. */
#define hello_task_PRIORITY (configMAX_PRIORITIES - 1)
/*******************************************************************************
 * Prototypes
 ******************************************************************************/
static void hello_task(void *pvParameters);

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Application entry point.
 */
int main(void)
{
    /* Init board hardware. */
    sc_ipc_t ipc;

    ipc = BOARD_InitRpc();
    BOARD_InitPins(ipc);
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();
    BOARD_InitMemory();

	//配置 LPSPI 的供电
    if (sc_pm_set_resource_power_mode(ipc, SC_R_SPI_3, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
    {
        PRINTF("Error: Failed to power on SPI3\r\n");
    }

	//设置 LPSPI 时钟源
    sc_pm_clock_enable(ipc, SC_R_SPI_3, SC_PM_CLK_PER, true, 0);
    if (CLOCK_SetIpFreq(kCLOCK_DMA_Lpspi3, SC_60MHZ) == 0)
    {
        PRINTF("Error: Failed to set SPI3 frequency\r\n");
    }
	PRINTF("LPUART_CLK_FREQ=%d.\r\n",LPUART_CLK_FREQ);

	//获取 LPSPI 默认配置
	LPSPI_MasterGetDefaultConfig(&masterConfig);
    //masterConfig.baudRate = 500000;//Default 500000 500K
    //masterConfig.bitsPerFrame = 8;//Default 8bit,16 is ok

	//完成对 LPSPI 工作状态配置,包括 SPI 时钟频率、相位、采样点、帧长等,这些包含在 lpspi_config 结构体中
    if (kStatus_Success != LPSPI_RTOS_Init(&handle, ADMA__LPSPI3, &masterConfig, LPUART_CLK_FREQ))
    {
         PRINTF("Failed to init SPI3.\r\n");
       	 vTaskSuspend(NULL);
    }

    if (xTaskCreate(hello_task, "Hello_task", configMINIMAL_STACK_SIZE + 100, NULL, hello_task_PRIORITY, NULL) !=
        pdPASS)
    {
        PRINTF("Task creation failed!.\r\n");
        while (1)
            ;
    }
    vTaskStartScheduler();
    for (;;)
        ;
}

/*!
 * @brief Task responsible for printing of "Hello world." message.
 */
static void hello_task(void *pvParameters)
{

	uint8_t config_cmds[32];
	uint8_t sizes = 8;
	uint32_t cnt = 0;
	
    config_cmds[0] = 0x1;
    config_cmds[1] = 0x2;
    config_cmds[2] = 0x3;
    config_cmds[3] = 0x4;
    config_cmds[4] = 0x5;
    config_cmds[5] = 0x6;
    config_cmds[6] = 0x7;
    config_cmds[7] = 0x8;
    config_cmds[8] = 0;
    
	memcpy(send_buffer, config_cmds, sizes);
	spi_data.dataSize = sizes;

	PRINTF("\r\n####################  spi3 master test ####################\n\r\n");
	PRINTF("	Build Time: %s--%s \n\r\n", __DATE__, __TIME__);
	PRINTF("##########################################################\r\n");

    for (;;)
    {
    	//延时1秒
		SDK_DelayAtLeastUs(1000000, SystemCoreClock);

		if (kStatus_Success != LPSPI_RTOS_TransferBlocking(&handle, &spi_data))//自构建阻塞,可以发送数据
		//if (kStatus_Success != LPSPI_RTOS_Transfer(&handle, &spi_data))//默认非阻塞,不能发送数据卡在函数里面
		{
			PRINTF("Command Transmission fails.\r\n");
			vTaskSuspend(NULL);
		}
		PRINTF("send %d ok.\r\n",++cnt);
        //vTaskSuspend(NULL);
    }
}
void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig)
{
    assert(masterConfig != NULL);

    /* Initializes the configure structure to zero. */
    (void)memset(masterConfig, 0, sizeof(*masterConfig));

    masterConfig->baudRate     = 500000;
    masterConfig->bitsPerFrame = 8;
    masterConfig->cpol         = kLPSPI_ClockPolarityActiveHigh;
    masterConfig->cpha         = kLPSPI_ClockPhaseFirstEdge;
    masterConfig->direction    = kLPSPI_MsbFirst;

    masterConfig->pcsToSckDelayInNanoSec        = 1000000000U / masterConfig->baudRate * 2U;
    masterConfig->lastSckToPcsDelayInNanoSec    = 1000000000U / masterConfig->baudRate * 2U;
    masterConfig->betweenTransferDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;

    masterConfig->whichPcs           = kLPSPI_Pcs0;
    masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow;

    masterConfig->pinCfg        = kLPSPI_SdiInSdoOut;
    masterConfig->dataOutConfig = kLpspiDataOutRetained;
}

        devices/MIMX8QX6/drivers/fsl_lpspi_freertos.c

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;
}

        devices/MIMX8QX6/drivers/fsl_lpspi_freertos.h

status_t LPSPI_RTOS_TransferBlocking(lpspi_rtos_handle_t *handle, lpspi_transfer_t *transfer);

 A35代码修改

        fsl-imx8qxp-mek.dtsi,打开spi0从模式,spi3注释关闭。

        pinctrl_lpspi0: lpspi0grp {
            fsl,pins = <
                SC_P_SPI0_SCK_ADMA_SPI0_SCK 0x0600004c
                SC_P_SPI0_SDO_ADMA_SPI0_SDO 0x0600004c
                SC_P_SPI0_SDI_ADMA_SPI0_SDI 0x0600004c
                SC_P_SPI0_CS0_ADMA_SPI0_CS0 0x0600004c

            >;
        };

&lpspi0 {
    #address-cells = <1>;
    #size-cells = <0>;
    fsl,spi-num-chipselects = <1>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_lpspi0>;
    spi-slave;
    status = "okay";
};

运行测试

        编译freertos_hello,M4中tftp下载运行,然后boot启动A35进入shell界面,运行内核和用户测试程序:

        上面测试结果是M4的spi3做主模式,从模式待研究。

        使用下面韬睿的代码设置lpspi_config,不能发送数据,cpol和cpha有差异:

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,
};

        默认的LPSPI_RTOS_Transfer函数不能发送数据问题,设置.rxData = NULL,发送一包数据后,不能退出发送状态,卡在xSemaphoreTake函数:

status_t LPSPI_RTOS_Transfer(lpspi_rtos_handle_t *handle, lpspi_transfer_t *transfer)
{
    status_t status;

    /* Lock resource mutex */
    if (xSemaphoreTake(handle->mutex, portMAX_DELAY) != pdTRUE)
    {
        return kStatus_LPSPI_Busy;
    }

    status = LPSPI_MasterTransferNonBlocking(handle->base, &handle->drv_handle, transfer);
    if (status != kStatus_Success)
    {
        (void)xSemaphoreGive(handle->mutex);
        return status;
    }
    /* Wait for transfer to finish */
    if (xSemaphoreTake(handle->event, portMAX_DELAY) != pdTRUE)
    {
        return kStatus_LPSPI_Error;
    }

    /* Unlock resource mutex */
    (void)xSemaphoreGive(handle->mutex);

    /* Return status captured by callback function */
    return handle->async_status;
}

        这是为何呢?

        参考master模式修改为slave模式,接收数据,第一次没有收到数据,第二次以后返回busy状态,改为阻塞还是busy,LPSPI_GetStatusFlags

	LPSPI_SlaveTransferNonBlocking
    /* Check that we're not busy.*/
    if (handle->state == (uint8_t)kLPSPI_Busy)
    {
    	PRINTF("error lpspi busy.\r\n");
        return kStatus_LPSPI_Busy;
    }

猜你喜欢

转载自blog.csdn.net/TSZ0000/article/details/123740779
今日推荐