MQX之SPI使用

硬件:FRDM_K64F
软件:Freescale_MQX_4_1_1
实现目的:通过SPI接口发送数据

步骤:
1)mqx中SPI例子里只有Twr板的,所以这里参考spi_twrk64f120m例子。可以先复制一份出来,将其更名为spi_frdmk64f120m,然后打开此工程。注意Twr_K64和FRDM_K64的默认printf串口不一样,所以对复制后的工程要做修改一下。
这里写图片描述
这样spi的例子就可以直接跑在frdm_k64上了。打开串口调试助手,可以显示出相关信息。
当然原来的twr-k64是配置twr-mem一起使用的,因为操作的是spi flash,用frdm-k64的话就没法实现这个功能了。

我这里为了方便,在原hellworld的代码基础上加入spi的部分。

2)user_config.h文件中将BSPCFG_ENABLE_SPI0 定义为1

#define BSPCFG_ENABLE_SPI0       1  // wenxue 0->1  20151020 for SPI test on frdm_k64f

这个定义为1的话,那么就会:

#if BSPCFG_ENABLE_SPI0
    _io_spi_install("spi0:", &_bsp_spi0_init);
#endif

3)修改hello.c 加入spi部分:

/*HEADER**********************************************************************
*
* Copyright 2008 Freescale Semiconductor, Inc.
* Copyright 1989-2008 ARC International
*
* This software is owned or controlled by Freescale Semiconductor.
* Use of this software is governed by the Freescale MQX RTOS License
* distributed with this Material.
* See the MQX_RTOS_LICENSE file distributed for more details.
*
* Brief License Summary:
* This software is provided in source form for you to use free of charge,
* but it is not open source software. You are allowed to use this software
* but you cannot redistribute it or derivative works of it in source form.
* The software may be used only in connection with a product containing
* a Freescale microprocessor, microcontroller, or digital signal processor.
* See license agreement file for full license terms including other
* restrictions.
*****************************************************************************
*
* Comments:
*
*   This file contains the source for the hello example program.
*
*
*END************************************************************************/

#include <mqx.h>
#include <bsp.h> 
#include <fio.h>


#if ! BSPCFG_ENABLE_IO_SUBSYSTEM
#error This application requires BSPCFG_ENABLE_IO_SUBSYSTEM defined non-zero in user_config.h. Please recompile BSP with this option.
#endif


#ifndef BSP_DEFAULT_IO_CHANNEL_DEFINED
#error This application requires BSP_DEFAULT_IO_CHANNEL to be not NULL. Please set corresponding BSPCFG_ENABLE_TTYx to non-zero in user_config.h and recompile BSP with this option.
#endif

 #if ! BSPCFG_ENABLE_SPI0
    #error This application requires BSPCFG_ENABLE_SPI0 defined non-zero in user_config.h. Please recompile kernel with this option.
 #else
    #define TEST_CHANNEL "spi0:"
 #endif



/* Task IDs */
#define HELLO_TASK 5

extern void hello_task(uint32_t);


const TASK_TEMPLATE_STRUCT  MQX_template_list[] = 
{ 
    /* Task Index,   Function,   Stack,  Priority, Name,     Attributes,          Param, Time Slice */
    { HELLO_TASK,   hello_task, 1500,   8,        "hello",  MQX_AUTO_START_TASK, 0,     0 },
    { 0 }
};

/*TASK*-----------------------------------------------------
* 
* Task Name    : hello_task
* Comments     :
*    This task prints " Hello World "
*
*END*-----------------------------------------------------*/
void hello_task
    (
        uint32_t initial_data
    )
{
    (void)initial_data; /* disable 'unused variable' warning */
    MQX_FILE_PTR           spifd;
    uint32_t               param,result;
    uint8_t buffer[]={0x55,0x02};

    printf("Hello World\n"); 

    printf ("\n-------------- SPI driver example --------------\n\n");
    printf ("This example application demonstrates usage of SPI driver.\n");

    /* Open the SPI driver */
    spifd = fopen (TEST_CHANNEL, NULL);

    if (NULL == spifd)
    {
        printf ("Error opening SPI driver!\n");
        _time_delay (200L);
        _task_block ();
    }

    /* Display baud rate */
    printf ("Current baud rate ... ");
    if (SPI_OK == ioctl (spifd, IO_IOCTL_SPI_GET_BAUD, &param))
    {
        printf ("%d Hz\n", param);
    }
    else
    {
        printf ("ERROR\n");
    }

     /* Set a different rate */
    param = 500000;
    printf ("Changing the baud rate to %d Hz ... ", param);
    if (SPI_OK == ioctl (spifd, IO_IOCTL_SPI_SET_BAUD, &param))
    {
        printf ("OK\n");
    }
    else
    {
        printf ("ERROR\n");
    }

    /* Display baud rate */
    printf ("Current baud rate ... ");
    if (SPI_OK == ioctl (spifd, IO_IOCTL_SPI_GET_BAUD, &param))
    {
        printf ("%d Hz\n", param);
    }
    else
    {
        printf ("ERROR\n");
    }

    while(1)
    {
     /* Write instruction */
     result = fwrite (buffer, 1, 1, spifd);
     _time_delay(100);
    }

    _task_block();
}

/* EOF */

4)spi0 用具体哪几个引脚,可以在init_gpio.c文件的_bsp_dspi_io_init()函数中修改:

_mqx_int _bsp_dspi_io_init
(
    uint32_t dev_num
)
{
    SIM_MemMapPtr   sim = SIM_BASE_PTR;
    PORT_MemMapPtr  pctl;

    switch (dev_num)
    {
        case 0:
            /* Configure GPIOD for DSPI0 peripheral function */
            pctl = (PORT_MemMapPtr)PORTD_BASE_PTR;

            pctl->PCR[0] = PORT_PCR_MUX(2);     /* DSPI0.PCS0   */
            pctl->PCR[1] = PORT_PCR_MUX(2);     /* DSPI0.SCK    */
            pctl->PCR[2] = PORT_PCR_MUX(2);     /* DSPI0.SOUT   */
            pctl->PCR[3] = PORT_PCR_MUX(2);     /* DSPI0.SIN    */

            /* Enable clock gate to DSPI0 module */
            sim->SCGC6 |= SIM_SCGC6_SPI0_MASK;
            break;

        case 1:

这里写图片描述

实验现象如下:

这里写图片描述

常见问题总结:
1)SPI 默认的参数在哪里设置?
这里写图片描述

此数据结构的定义在spi.h中
这里写图片描述

这里写图片描述

2)如何设置波特率?
通过ioctl IO_IOCTL_SPI_SET_BAUD命令即可。注意执行ioctl后并不是立刻就更改了波特率配置,而是在调用的spi发送函数里才做的修改。
调用_dspi_dma_setparam()这个函数

if (dev_data->PARAMS_DIRTY)
    {
        error_code = driver_data->DEVIF->SETPARAM(driver_data->DEVIF_DATA, &(dev_data->PARAMS));
        if (error_code != MQX_OK)
        {
            _task_set_error(error_code);
            return IO_ERROR;
        }
        dev_data->PARAMS_DIRTY = FALSE;
    }

3)如何修改SPI 极性和相位
通过ioctl IO_IOCTL_SPI_SET_MODE 命令即可,参数如下:
这里写图片描述
比如设置为SPI_CLK_POL_PHA_MODE1,波形如下:
这里写图片描述

4)ioctl IO_IOCTL_SPI_SET_ENDIAN 作用是什么?
用来控制数据时MSB first还是LSB first。
这里写图片描述

ATTR :0 表示大端 1表示小端
这里写图片描述

_dspi_dma_setparam()->_dspi_ctar_params()

 /* Endianess */
    if ((params->ATTR & SPI_ATTR_ENDIAN_MASK) == SPI_ATTR_LITTLE_ENDIAN)
        ctar |= DSPI_CTAR_LSBFE_MASK;

5)SPI 和eDMA关系?
在frdmk64f.h中,我们可以看到

#ifndef BSPCFG_DSPI0_USE_DMA
    #define BSPCFG_DSPI0_USE_DMA                1
#endif

注意对SPI1和SPI2

#ifndef BSPCFG_DSPI1_USE_DMA
    #define BSPCFG_DSPI1_USE_DMA                0
#endif

#ifndef BSPCFG_DSPI2_USE_DMA
    #define BSPCFG_DSPI2_USE_DMA                0
#endif

所以:

#if BSPCFG_DSPI0_USE_DMA

static const DSPI_DMA_INIT_STRUCT _bsp_dspi0_init = {
    0,                            /* SPI channel */
    CM_CLOCK_SOURCE_BUS,          /* Relevant module clock source */
    BSP_DSPI0_DMA_RX_CHANNEL,     /* DMA channel for RX */
    BSP_DSPI0_DMA_TX_CHANNEL,     /* DMA channel for TX */
    BSP_DSPI0_DMA_RX_SOURCE,      /* Source to be used with RX channel */
    BSP_DSPI0_DMA_TX_SOURCE       /* Source to be used with TX channel */
};

const SPI_INIT_STRUCT _bsp_spi0_init = {
    &_spi_dspi_dma_devif,         /* Low level driver interface */
    &_bsp_dspi0_init,             /* Low level driver init data */
    {                             /* Default parameters: */
        10000000,                     /* Baudrate */
        SPI_CLK_POL_PHA_MODE0,        /* Mode */
        8,                            /* Frame size */
        1,                            /* Chip select */
        0,                            /* Attributes */
        0xFFFFFFFF                    /* Dummy pattern */
    }
};

#else /* BSPCFG_DSPI0_USE_DMA */

static const DSPI_INIT_STRUCT _bsp_dspi0_init = {
    0,                            /* SPI channel */
    CM_CLOCK_SOURCE_BUS           /* Relevant module clock source */
};

const SPI_INIT_STRUCT _bsp_spi0_init = {
    &_spi_dspi_devif,             /* Low level driver interface */
    &_bsp_dspi0_init,             /* Low level driver init data */
    {                             /* Default parameters: */
        10000000,                     /* Baudrate */
        SPI_CLK_POL_PHA_MODE0,        /* Mode */
        8,                            /* Frame size */
        1,                            /* Chip select */
        DSPI_ATTR_USE_ISR,            /* Attributes */
        0xFFFFFFFF                    /* Dummy pattern */
    }
};

#endif /* DSPI0_USE_DMA */

如果不使用eDMA,可以在user_config.h 中

#define BSPCFG_DSPI0_USE_DMA 0

另外当SPI使用eDMA时,如果eDMA还用作其他功能,那么可能出错。
这里写图片描述
关于这个问题的讨论可以参考:https://community.freescale.com/thread/323538

6)是否支持SLAVE模式?
在_dspi_setparam()或者_dspi_dma_setparam()函数中:
会判断是否为MASTER模式,所以不支持SLAVE模式

 /* Transfer mode */
    if ((params->ATTR & SPI_ATTR_TRANSFER_MODE_MASK) != SPI_ATTR_MASTER_MODE)
        return SPI_ERROR_TRANSFER_MODE_INVALID;

    /* Set master mode */
    dspi_ptr->MCR |= DSPI_MCR_MSTR_MASK;

在MQX_Release_Notes.pdf中也说了:
这里写图片描述

如果想在MQX里使用SPI Slave模式,可以有两种方法:1)使用spi_legacy driver;2)Write your own driver for spi slave using direct accesses to DSPI module registers and call it from an MQX task. 自己直接操作寄存器去写驱动

7)SPI FIFO设置问题
这里写图片描述
对K64 SPI FIFO
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值