MQX之SPI使用

来源:互联网 发布:电冰箱直播软件 编辑:程序博客网 时间:2024/05/21 03:29

硬件: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 5extern 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_DMAstatic 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 0
原创粉丝点击