采用IMXRT1020驱动ATWINC1500模块

        ATWINC1500模块是一个低功耗的物联网模块。它的官方页面如下,

https://www.microchip.com/en-us/product/ATWINC1500

其中芯片的官方页面如下,

https://www.microchip.com/en-us/product/ATWINC1500-IC

这里我们重点介绍它的移植,关于它的介绍,大家可以参考官方网页中的如下这两篇文档,

 在模块的官方页面中,有如下一篇文档,

 这篇文档就是教大家如何把1500移植到单片机中,我们这篇文章也是根据这篇文档进行移植的。

        打开这篇文档,首先我们需要安装MLA框架,

 点击上面的标红的link进入如下链接,

Microchip Libraries for Applications (MLA) | Microchip Technology

 接下来进行下载,

下载完成后,安装包如上,安装过程就不在这里说了,因为没什么特殊的,基本都是下一步就好。

        下载完成后,大家可以在如下路径下看到1500的驱动代码。

 这些驱动代码在后续步骤中需要我们拷贝到具体工程中。

         接下来就开始我们正式的移植工作了,首先我们看下1500模块和单片机接口,如下,

 除此之外,要驱动1500需要的资源在文档中也列出了,

 那么具体SPI接口、定时器、中断应该如何配置?别急,这个我们后面会介绍。

        接下来我们用MCUXpressoIDE导入一个SDK example,这里我们选择以轮询方式实现SPI通信的例程导入,

 然后将1500驱动代码文件夹复制到我们所建工程的路径下,如下,

接下来打开winc1500_driver_config.h文件,按照手册我们需要配置HOST_MCU_BIG_ENDIAN和M2M_POINTER_SIZE_IN_BYTES,

根据1020手册我们知道这款芯片只支持小端模式,所以HOST_MCU_BIG_ENDIAN保持注释状态;而M2M_POINTER_SIZE_IN_BYTES只需要按照注释运行int x = sizeof(int *),然后按照x的取值进行定义即可。发现x为4。所以,

然后根据文档我们创建一个wf_mcu_driver_stub.c的源文件,

然后我们会在这个文件中实现一些函数,这些函数和具体使用的单片机相关的并且驱动代码会调用这些函数,它们被称为桩函数,也就是说这些函数的声明已经在驱动代码中写好了,格式也规定好了,我们只需要实现它。接下来我们需要把这些桩函数全部实现!

         首先,我们需要实现SPI接口的读写函数。根据文档,我们选择SPI的模式0并且SPI时钟设置8M。

 在SPI的初始化代码中,我们可以通过TRANSFER_BAUDRATE宏定义修改时钟频率。

而SPI的模式0,也在如下代码中配置了,

 初始化SPI结束后,我们就可以实现SPI读写函数了,如下,

void m2mStub_SpiTxRx(uint8_t *p_txBuf,
                    uint16_t txLen,
                    uint8_t *p_rxBuf,
                    uint16_t rxLen){

	status_t status;

	if(txLen){
    	/*Start master transfer, transfer data to slave.*/
		masterXfer.txData   = p_txBuf;
		masterXfer.rxData   = NULL;
		masterXfer.dataSize = txLen;
		masterXfer.configFlags =
			EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;

		status=LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);
		if(status!=kStatus_Success)
			PRINTF("SPI WRITE FAIL\r\n");
    }

	if(rxLen){
		/* Start master transfer, receive data from slave */
		masterXfer.txData   = NULL;
		masterXfer.rxData   = p_rxBuf;
		masterXfer.dataSize = rxLen;
		masterXfer.configFlags =
			EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
		status=LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);
		if(status!=kStatus_Success){
			PRINTF("SPI READ FAIL\r\n");
			PRINTF("status=%d\r\n",status);
		}
	}
}

这里的LPSPI_MasterTransferBlocking函数是一个阻塞函数,也就是该函数只有在传输完成后才会返回,但这里注意,在实际测试发现,连续调用这个函数读数据时,会出现总线忙的返回,如下,

 所以我在该函数的读操作最后加了如下红框的判断,

 也就是完成传输标志位拉高后再返回。

        接下来我们需要实现定时器的桩函数,该定时器的精度是1ms,并且其中有一个32位的变量作为计数器,该计数器每隔1ms加一,当加到0xffffffff再返回到0,重新自增。该函数返回这个计数器。

我们这个轮询方式实现SPI的例程中,包含一个定时器,SysTick,我们就用这个定时器来做,在代码中已经将该定时器设定成了每一秒进一次中断,如下,

 并且也已经有一个32位的无符号变量作为计数器,

我们只要在定时器中断函数中对g_systickCounter进行自增并且在定时器的桩函数中返回该计数器变量即可,

 

        接下来我们实现GPIO的桩函数,根据文档我们需要实现三个GPIO的桩函数,分别控制CE、RESET、SPI的SS,这里SPI接口的SS引脚已经由SPI接口控制,所以控制SS的桩函数我们不用实现,但同时我们需要在驱动代码中删掉调用该函数的代码。如下,

 GPIO的初始化代码如下,

    /* Init CE */
	sw_config.direction=kGPIO_DigitalOutput;
	sw_config.interruptMode=kGPIO_NoIntmode;
	sw_config.outputLogic=0;
	GPIO_PinInit(CE_GPIO, CE_GPIO_PIN, &sw_config);

	/* Init RESET */
	sw_config.direction=kGPIO_DigitalOutput;
	sw_config.interruptMode=kGPIO_NoIntmode;
	sw_config.outputLogic=0;
	GPIO_PinInit(RESET_GPIO, RESET_GPIO_PIN, &sw_config);

桩函数代码如下,

void m2mStub_PinSet_SPI_SS(t_m2mWifiPinAction action){

}

void m2mStub_PinSet_RESET(t_m2mWifiPinAction action)
{
    if (action == M2M_WIFI_PIN_LOW)
    {
    	GPIO_PinWrite(RESET_GPIO, RESET_GPIO_PIN, 0U);
    }
    else
    {
    	GPIO_PinWrite(RESET_GPIO, RESET_GPIO_PIN, 1U);
    }
}

void m2mStub_PinSet_CE(t_m2mWifiPinAction action)
{
    if (action == M2M_WIFI_PIN_LOW)
    {
    	GPIO_PinWrite(CE_GPIO, CE_GPIO_PIN, 0U);
    }
    else
    {
    	GPIO_PinWrite(CE_GPIO, CE_GPIO_PIN, 1U);
    }
}

        接下来我们实现中断的桩函数,根据文档我们需要一个下降沿触发的中断,

 所以我们在中断初始化时,设置中断模式为下降沿触发,

/* Init IRQN */
	sw_config.direction=kGPIO_DigitalInput;
	sw_config.interruptMode=kGPIO_IntFallingEdge;
	sw_config.outputLogic=0;
    EnableIRQ(GPIO1_Combined_0_15_IRQn);
    GPIO_PinInit(BOARD_INITPINS_wifi_irq_GPIO, BOARD_INITPINS_wifi_irq_GPIO_PIN, &sw_config);

这里我们用GPIO1的5引脚作为中断引脚,根据1020手册,该中断是在GPIO1的联合中断中处理的,

 根据文档要求,单片机的中断函数需要调用m2m_EintHandler(),

 所以我们实现的中断处理函数如下,

void GPIO1_Combined_0_15_IRQHandler(void)
{
	/* clear the interrupt status */
    GPIO_PortClearInterruptFlags(BOARD_INITPINS_wifi_irq_GPIO, 1U << BOARD_INITPINS_wifi_irq_GPIO_PIN);
    m2m_EintHandler();
    SDK_ISR_EXIT_BARRIER;
}

禁止和使能中断的桩函数如下,

void m2mStub_EintEnable(void){
	GPIO_PortEnableInterrupts(BOARD_INITPINS_wifi_irq_GPIO, 1U << BOARD_INITPINS_wifi_irq_GPIO_PIN);
}

void m2mStub_EintDisable(void){
	GPIO_PortDisableInterrupts(BOARD_INITPINS_wifi_irq_GPIO, 1U << BOARD_INITPINS_wifi_irq_GPIO_PIN);
}

        代码部分先告一段落,接下来大家不要忘了分配引脚,

 对于SPI引脚和UART引脚,他们的配置我们不需要动,对于三个GPIO引脚,我们可以参考如下两个SDK example去配置,这里就不详细说了,

另外点开winc1500_api.h文件,这里我们需要把dprintf设置成我们调试的打印函数PRINTF,如下,

 然后我们需要把官方提供给我们的demo复制到我们的工程目录下,这部分参考下面的官方文档,

 这篇文档也是在模块的官方页面中。官方提供的demo在如下路径下,

我们直接把src目录拷贝到工程的source路径下, 

接下来要把winc1500文件夹作为源代码路径,编译的时候需要包括进去,如下, 

并且要在include路径中添加我们的winc1500文件夹,src文件夹及其子文件夹,也就是但凡文件夹中由h文件的都需要加入,

 然后我们编辑main.c文件,注意要把winc1500_api.h加入到文件中,

 文档中也提供了一个运行demo的main.c文件的模板,

也就是说,我们要运行demo,main文件大体就长这个样,当然我们也要根据具体情况做出调整,我的main文件如下,供大家参考,

#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "fsl_lpspi.h"
#include "pin_mux.h"
#include "board.h"
#include "fsl_gpio.h"
#include "myheader.h"

#include "fsl_common.h"
#if ((defined FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT))
#include "fsl_intmux.h"
#endif

#include "winc1500_api.h"
#include "demo_config.h"

/*******************************************************************************
 * Variables
 ******************************************************************************/
lpspi_transfer_t masterXfer;
volatile uint32_t g_systickCounter  = 0U;
gpio_pin_config_t sw_config;
/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/
void SysTick_Handler(void)
{
    if (g_systickCounter == 0xffffffff)
    {
        g_systickCounter=0;
    }else
    	g_systickCounter++;
}

void board_init(){
	BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitDebugConsole();
}

void spi_init(){
    /*Set clock source for LPSPI*/
    CLOCK_SetMux(kCLOCK_LpspiMux, EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT);
    CLOCK_SetDiv(kCLOCK_LpspiDiv, EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER);

    uint32_t srcClock_Hz;
    lpspi_master_config_t masterConfig;


    /*Master config*/
    LPSPI_MasterGetDefaultConfig(&masterConfig);
    masterConfig.baudRate = TRANSFER_BAUDRATE;
    masterConfig.whichPcs = EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT;

    srcClock_Hz = LPSPI_MASTER_CLK_FREQ;
    LPSPI_MasterInit(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterConfig, srcClock_Hz);
}

void SysTick_init(){
    if (SysTick_Config(SystemCoreClock / 1000U))
    {
        while (1)
        {
        }
    }
}

void gpio_init(){
    /* Init IRQN */
	sw_config.direction=kGPIO_DigitalInput;
	sw_config.interruptMode=kGPIO_IntFallingEdge;
	sw_config.outputLogic=0;
    EnableIRQ(GPIO1_Combined_0_15_IRQn);
    GPIO_PinInit(BOARD_INITPINS_wifi_irq_GPIO, BOARD_INITPINS_wifi_irq_GPIO_PIN, &sw_config);

    /* Init CE */
	sw_config.direction=kGPIO_DigitalOutput;
	sw_config.interruptMode=kGPIO_NoIntmode;
	sw_config.outputLogic=0;
	GPIO_PinInit(CE_GPIO, CE_GPIO_PIN, &sw_config);

	/* Init RESET */
	sw_config.direction=kGPIO_DigitalOutput;
	sw_config.interruptMode=kGPIO_NoIntmode;
	sw_config.outputLogic=0;
	GPIO_PinInit(RESET_GPIO, RESET_GPIO_PIN, &sw_config);
}

int main(void)
{
	board_init();
	gpio_init();
	spi_init();
	SysTick_init();

	m2m_wifi_init();

	while (1)
	{
		ApplicationTask();
		m2m_wifi_task();
	}
}

另外,官方给我们提供了很多demo,我们具体想要运行哪个,需要在demo_config.h中规定,

默认是运行检测ap的demo。大家在编译之前,根据情况决定是否将ApplicationTask函数中的printf换成PRINTF,防止打印不出信息。另外有些头文件和全局变量的声明大家也要注意,不然编译报错,诸如下图所示。

 如果没有问题的话,终端会打印出如下内容。

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: i.MXRT1176是一款高性能的处理器,支持多种外设接口,其中包括Mipi-CSI2接口和UVC功能。 Mipi-CSI2是一种用于传输摄像头数据的串行接口标准。它可以实现高速、低功耗的数据传输,广泛应用于移动设备和嵌入式系统中。i.MXRT1176的Mipi-CSI2接口可以与兼容的摄像头模块进行连接,以便从摄像头获取图像数据。 UVC(USB Video Class)是一种用于通过USB接口传输视频数据的标准。它可以让USB设备(例如计算机或其他支持UVC的设备)直接识别和使用摄像头,简化了设备之间的连接和通信。i.MXRT1176的UVC功能可以将通过Mipi-CSI2接口获取的摄像头数据转换为符合UVC标准的视频流,以便被连接的设备进行识别和使用。 通过i.MXRT1176的Mipi-CSI2 to UVC功能,我们可以方便地将摄像头模块的图像数据转换为USB视频流,实现将摄像头接口扩展到支持UVC的设备,如计算机、智能电视等。这样,我们可以方便地将摄像头用于视频通信、图像采集和人机互动等应用领域。 总之,i.MXRT1176的Mipi-CSI2 to UVC功能提供了一种简单、高效的解决方案,使得摄像头数据可以通过USB接口直接传输给其他设备,为视频应用的开发和应用提供了更多的可能性。 ### 回答2: IMXRT1176 是恩智浦(NXP)公司推出的一款高性能 Arm Cortex-M7 微控制器。它具有丰富的外设接口和强大的计算能力,可广泛应用于各种嵌入式系统中。 MIPI-CSI2 是一种通信接口标准,用于将摄像头传感器与处理器之间的数据传输。它通过传输高清视频和图像数据,实现了低功耗、高带宽、高质量的图像传输。 UVC(USB Video Class)是一种标准协议,用于视频设备与计算机之间的通信。它允许将视频设备连接到计算机,并以 USB 接口的形式传输图像或视频数据。 IMXRT1176 Mipi-CSI2 to UVC 是指将IMXRT1176微控制器与摄像头传感器之间的视频数据经过Mipi-CSI2接口传输,并通过UVC协议将视频数据传输到连接的计算机。 通过这种方式,我们可以在IMXRT1176微控制器上实现摄像头数据的采集和处理,然后将处理后的视频数据传输到计算机,并通过UVC协议对其进行解码和显示。这使得开发者可以方便地在嵌入式系统中使用摄像头,并实现图像或视频的实时采集、处理和显示。 总之,IMXRT1176 Mipi-CSI2 to UVC 提供了一种方便高效的解决方案,使得在嵌入式系统中使用摄像头变得更加容易和灵活。 ### 回答3: IMXRT1176是一款高性能的嵌入式处理器,而MIPI-CSI2和UVC是两种不同的图像传输接口。 MIPI-CSI2是一种用于连接图像传感器和图像处理器的接口标准。它使用串行传输协议,可以实现高速、低功耗的图像传输。MIPI-CSI2支持多通道数据传输,并且提供了丰富的控制和配置选项,以满足不同应用场景的要求。因此,IMXRT1176可以通过MIPI-CSI2接口与图像传感器进行通信,获取高质量的图像数据。 UVC是一种USB设备类别,它定义了一套用于视频采集和图像传输的标准协议。通过UVC协议,可以将图像数据通过USB接口传输到计算机上,同时还可以实现对图像的控制和配置。这样,计算机可以直接从IMXRT1176通过UVC接口获取图像数据,无需额外的驱动程序。 因此,IMXRT1176 MIPI-CSI2 to UVC的意思就是将IMXRT1176处理器与图像传感器通过MIPI-CSI2接口连接,然后将获取的图像数据通过UVC接口传输给计算机。这样一来,我们就可以在计算机上实时查看、录制和处理来自图像传感器的图像数据,为各种应用场景带来更便利和灵活的图像处理能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值