本文主要讲述如何在 STM32F407 上 移植 MiCO 系统,以此介绍:如何将 MiCO 系统移植到一个新的 MCU 硬件平台,保证 MiCO 应用工程可以正常运行。移植的主要工作:实现驱动接口功能。
阅读本文,开发者应具备一定的硬件知识,了解 MCU 架构,了解 Cortex-M 系列指令,熟悉 IAR 开发环境(部分基础操作不做详细介绍)。
1. 明确MiCO支持的MCU内核: 目前 MiCO 已经支持的内核有:Cortex-M3 , Cortex-M4, Cortex-M4F三个,所以基于本文进行 MiCO 移植时,要选 M3 或 M4 内核的 MCU 平台。
2. 明确MiCO所需FLASH和RAM大小: 目前 MiCO 系统移植要求 MCU 必须满足:RAM 不小于 96KB,片内 FLASH 不小于300KB,主频48MHZ以上,支持SDIO或SPI接口。
3.明确MiCO必需的外设接口:
4.明确 MiCO 支持的单 WLAN 模块型号: MiCO 支持的单 WLAN 模块型号:EMW1062,EMW1088。
5. 获取MCU厂商提供的底层驱动库
6. 下载MiCO SDK开发包: 至 mico.io 下载中心,下载 SDK 开发包,它集成了各种已经移植好的MCU工程,可以做参考。检查移植是否完成,可以使用 MiCO SDK 里的 bootloader 和 Demos(可用applicationwifi_uart)两个工程项目,其他工程项目都只是上层不同而已。
7. 准备移植用的开发板: 确认开发板是否满足MiCO移植要求,如: 是否是MiCO支持的MCU内核类型? WLAN模块正确连接吗(是否是MiCO已经支持的型号)? 片内FLASH,RAM大小满足吗? SPI FLASH 连接正确与否? UART 接口连接正确与否?等等。
8. 准备开发工具: MiCoder IDE v1.0或更高版本,J-Link或ST-link调试工具,串口调试工具,网络调试工具,可参考:第三方开发工具及驱动。
根据上节提到的开发板选用要求,同时为了避免开发板电路过于复杂,本次移植选择STM32F407ZET6最小系统开发板。购买开发板,点 这里。开发板详细资料获取,点 这里。
开发板主芯片选用 STM32F407ZET6,主频为168MHz,内置512KB Flash、192+4kB SRAM,开发板其他资源如图所示。
1.NRF24L01模块接口: 这是开发板板载的 NRF24L01 模块接口(U6),只要插入模块,我们便可以实现无线通信,从而使得我们板子具备了无线功能,但是这里需要2个模块和2个开发板同时工作才可以。如果只有1个开发板或1个模块,是没法实现无线通信的。
2.W25Q128 128M FLASH: 这是开发板外扩的 SPI FLASH 芯片(U11),容量为128Mbit,也就是16M字节,可用于存储字库和其他用户数据,满足大容量数据存储要求。当然如果觉得 16M 字节还不够用,你可以把数据存放在外部 SD 卡。
目前庆科支持的两种单射频无线模块是:EMW1062 和 EMW1088。
EMW1062 利用直接序列扩频和OFDM / CCK技术,实现无线调制解调功能,该模块集成2.4GHz IEEE802.11b/g/n(MAC/基带/射频),功率放大器(PA)和电源管理单元(PMU),SDIO2.0或SPI接口,3.3V单电源供电。 该模块的无线局域网符合IEEE802.11b/g/n标准。
EMW1088 是一款基于MARVELL88w8801芯片设计的产品。该芯片是一个高度集成的,单波段的(2.4GHz),符合IEEE 802.11n:1x1无线标准的系统级芯片(SoC,System-on-Chip),专门为支持下一代无线局域网产品的高通量数据传输速率而设计。
本次移植单射频模块选择EMW1062,EMW1088同样可以参考本次移植方法。
首先明确: MiCO分为Bootloader, 应用程序,和 RF 射频驱动三块。其中:
移植思路:
MiCO SDK 中的工程分为两大类:bootloader 引导程序和 Application 应用程序,这两段代码写在不同的flash分区中,分两次写入。那么MiCO系统运行流程也就和普通的STM32程序不同:
下面我们以hello world工程为例,来分析 MiCO 系统的运行流程,如图所示。
上图红色选中部分为移植时需要更改和实现的文件,主要包括 5 个文件夹:
1.platform_config.h: 当前平台的配置信息
2.platform.c文件:
3.platform.h文件:
4.memory.ld文件: 定义分配的内存 5.MKF407.mk文件:设计编译规则
1. 移植 Bootloader 引导程序
2. 移植 Demosapplicationwifi_uart示例程序
NAME := Board_NUCLEO_F411RE
修改为NAME := Board_MK407
WLAN_CHIP := 43362
WLAN_CHIP_REVISION := A2
WLAN_CHIP_FAMILY := 43362
WLAN_CHIP_FIRMWARE_VER := 5.90.230.12
注意: 本次移值开发板和 NUCLEO_F411RE 均使用EMW1062,不需修改,当使用EMW1088模块时候需要修改,修改参数可以参考 MK3288 板级支持包。
HOST_MCU_FAMILY := STM32F4xx #对应platform/MCU、STM32F4xx文件
HOST_MCU_VARIANT := STM32F411
HOST_MCU_PART_NUMBER := STM32F411CEY6
由于开发板选用STM32F407ZET6,仍使用ST公司的库函数,所以将以上参数修改为:
HOST_MCU_FAMILY := STM32F4xx
HOST_MCU_VARIANT := STM32F407
HOST_MCU_PART_NUMBER := STM32F407ZET6
6)选择wifi模块驱动方式:BUS := SDIO 或者 BUS := SPI
7)声明外部HSE:GLOBAL_DEFINES += HSE_VALUE=8000000
#系统使用8MHz外部震荡晶振
8)搜索路径声明:GLOBAL_LDFLAGS += -L ./board/NUCLEO_F411RE
修改为:GLOBAL_LDFLAGS += -L ./board/MK407
SHARED_WIFI_SPI_BUS := YES
如果使用共享模式,保留上述配置方法,一般不开启共享功能,建议使用单独SPI驱动wifi模块。
打开platform.c文件,下拉至最后,修改 MicoShouldEnterBootloader 函数.
注意:由于本开发板上没有 BOOT 和 STATUS 模式切换拨码开关,因此应用程序直接进入bootloader模式。
bool MicoShouldEnterBootloader(void)
{
// if(MicoGpioInputGet((mico_gpio_t)BOOT_SEL)==false && MicoGpioInputGet((mico_gpio_t)MFG_SEL)==true)
// return true;
// else
// return false;
return true;
}
#define HARDWARE_REVISION "1.0"
#define DEFAULT_NAME "NUCLEO"
#define MODEL "NUCLEO-F411RE"
将以参数修改为如下所示:
#define HARDWARE_REVISION "1.0"
#define DEFAULT_NAME "STM32"
#define MODEL "STM32-F407ZE"
#define MICO_WIFI_SHARE_SPI_BUS
声明开发板的外部晶振频率; 在 7.2.1 中 7) 已经配置了此参数: GLOBAL_DEFINES += HSE_VALUE=8000000
a.修改主频: #define MCU_CLOCK_HZ (100000000)
, 修改为 #define MCU_CLOCK_HZ (168000000)
b.修改PLL锁相环相关参数:
#define PLL_M_CONSTANT 16 /* PLLM = 16 */
#define PLL_N_CONSTANT 400 /* PLLN = 400 */
#define PLL_P_CONSTANT 4 /* PLLP = 4 */
#define PPL_Q_CONSTANT 7 /* PLLQ = 7 */
修改为
#define PLL_M_CONSTANT 8 /* PLLM = 16 */
#define PLL_N_CONSTANT 336 /* PLLN = 400 */
#define PLL_P_CONSTANT 2 /* PLLP = 4 */
#define PPL_Q_CONSTANT 7 /* PLLQ = 7 */
计算公式:
示例:8MHz*336/(8*2)=168MHz //系统主时钟
示例:8MHz*336/(8*7)=48MHz //USB时钟
const mico_logic_partition_t mico_partitions[] =
{
[MICO_PARTITION_BOOTLOADER] =
{
.partition_owner = MICO_FLASH_EMBEDDED,
.partition_description = "Bootloader",
.partition_start_addr = 0x08000000,
.partition_length = 0x8000, //32k bytes
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
},
[MICO_PARTITION_APPLICATION] =
{
.partition_owner = MICO_FLASH_EMBEDDED,
.partition_description = "Application",
.partition_start_addr = 0x0800C000,
.partition_length = 0x64000, //400k bytes
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
},
[MICO_PARTITION_RF_FIRMWARE] =
{
.partition_owner = MICO_FLASH_SPI,
.partition_description = "RF Firmware",
.partition_start_addr = 0x2000,
.partition_length = 0x3E000, //248k bytes
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
},
[MICO_PARTITION_OTA_TEMP] =
{
.partition_owner = MICO_FLASH_SPI,
.partition_description = "OTA Storage",
.partition_start_addr = 0x40000,
.partition_length = 0x70000, //448k bytes
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_EN,
},
[MICO_PARTITION_PARAMETER_1] =
{
.partition_owner = MICO_FLASH_SPI,
.partition_description = "PARAMETER1",
.partition_start_addr = 0x0,
.partition_length = 0x1000, // 4k bytes
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_EN,
},
[MICO_PARTITION_PARAMETER_2] =
{
.partition_owner = MICO_FLASH_SPI,
.partition_description = "PARAMETER2",
.partition_start_addr = 0x1000,
.partition_length = 0x1000, //4k bytes
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_EN,
}
};
platform_peripheral.h文件定义HAL层使用时,外设相关的类型定义,以及移植需要实现的接口函数。platform_mcu_peripheral.h文件定义外设使用的结构体,分为:
typedef enum
{
MICO_SYS_LED,
MICO_RF_LED,
BOOT_SEL,
MFG_SEL,
EasyLink_BUTTON,
STDIO_UART_RX,
STDIO_UART_TX,
FLASH_PIN_SPI_CS,
FLASH_PIN_SPI_CLK,
FLASH_PIN_SPI_MOSI,
FLASH_PIN_SPI_MISO,
MICO_GPIO_2,
MICO_GPIO_8,
MICO_GPIO_9,
MICO_GPIO_12,
MICO_GPIO_14,
MICO_GPIO_16,
MICO_GPIO_17,
MICO_GPIO_18,
MICO_GPIO_19,
MICO_GPIO_27,
MICO_GPIO_29,
MICO_GPIO_30,
MICO_GPIO_31,
MICO_GPIO_33,
MICO_GPIO_34,
MICO_GPIO_35,
MICO_GPIO_36,
MICO_GPIO_37,
MICO_GPIO_38,
MICO_GPIO_MAX, /* Denotes the total number of GPIO port aliases. Not a valid GPIO alias */
MICO_GPIO_NONE,
} mico_gpio_t;
可以按照自己的命名风格命名,删除如下定义:
#define MFG_SEL (MICO_GPIO_NONE)
#define MICO_RF_LED (MICO_GPIO_NONE)
#define BOOT_SEL (MICO_GPIO_NONE)
以便支持硬件方式选择程序进入的模式,bootloader模式或者application模式。
typedef enum
{
MICO_SPI_1,
MICO_SPI_MAX, /* Denotes the total number of SPI port aliases. Not a valid SPI alias */
MICO_SPI_NONE,
} mico_spi_t;
typedef enum
{
MICO_I2C_1,
MICO_I2C_MAX, /* Denotes the total number of I2C port aliases. Not a valid I2C alias */
MICO_I2C_NONE,
} mico_i2c_t;
typedef enum
{
MICO_PWM_MAX, /* Denotes the total number of PWM port aliases. Not a valid PWM alias */
MICO_PWM_NONE,
} mico_pwm_t;
typedef enum
{
MICO_ADC_1,
MICO_ADC_2,
MICO_ADC_3,
MICO_ADC_MAX, /* Denotes the total number of ADC port aliases. Not a valid ADC alias */
MICO_ADC_NONE,
} mico_adc_t;
typedef enum
{
MICO_UART_1,
MICO_UART_2,
MICO_UART_MAX, /* Denotes the total number of UART port aliases. Not a valid UART alias */
MICO_UART_NONE,
} mico_uart_t;
#ifdef BOOTLOADER
#define STDIO_UART (MICO_UART_2)
#define STDIO_UART_BAUDRATE (115200)
#else
#define STDIO_UART (MICO_UART_2)
#define STDIO_UART_BAUDRATE (115200)
#endif
#define UART_FOR_APP (MICO_UART_2)
#define MFG_TEST (MICO_UART_2)
#define CLI_UART (MICO_UART_2)
const platform_gpio_t platform_gpio_pins[] =
{
/* Common GPIOs for internal use */
[MICO_SYS_LED] = { GPIOF, 9 },
[MICO_RF_LED] = { GPIOF, 10},
[BOOT_SEL] = { GPIOF, 1 },
[MFG_SEL] = { GPIOF, 0 },
[EasyLink_BUTTON] = { GPIOE, 4 }, //key0
[STDIO_UART_RX] = { GPIOA, 3 },
[STDIO_UART_TX] = { GPIOA, 2 },
[FLASH_PIN_SPI_CS ] = { GPIOB, 14 },
[FLASH_PIN_SPI_CLK ] = { GPIOB, 3 },
[FLASH_PIN_SPI_MOSI] = { GPIOB, 5 },
[FLASH_PIN_SPI_MISO] = { GPIOB, 4 },
/* GPIOs for external use */
[MICO_GPIO_2] = { GPIOG, 7 },
[MICO_GPIO_8] = { GPIOA , 2 },
[MICO_GPIO_9] = { GPIOA, 1 },
[MICO_GPIO_12] = { GPIOA, 3 },
[MICO_GPIO_14] = { GPIOA, 0 },
[MICO_GPIO_16] = { GPIOC, 13 },
[MICO_GPIO_17] = { GPIOB, 10 },
[MICO_GPIO_18] = { GPIOB, 9 },
[MICO_GPIO_19] = { GPIOB, 12 },
[MICO_GPIO_27] = { GPIOA, 12 },
[MICO_GPIO_29] = { GPIOA, 10 },
[MICO_GPIO_30] = { GPIOA, 9 },
[MICO_GPIO_31] = { GPIOB, 8 },
[MICO_GPIO_33] = { GPIOB, 13 },
[MICO_GPIO_34] = { GPIOA, 5 },
[MICO_GPIO_35] = { GPIOA, 11 },
[MICO_GPIO_36] = { GPIOB, 1 },
[MICO_GPIO_37] = { GPIOB, 0 },
[MICO_GPIO_38] = { GPIOA, 4 },
};
const platform_i2c_t platform_i2c_peripherals[] =
{
[MICO_I2C_1] =
{
.port = I2C1,
.pin_scl = &platform_gpio_pins[MICO_GPIO_18],
.pin_sda = &platform_gpio_pins[MICO_GPIO_17],
.peripheral_clock_reg = RCC_APB1Periph_I2C1,
.tx_dma = DMA1,
.tx_dma_peripheral_clock = RCC_AHB1Periph_DMA1,
.tx_dma_stream = DMA1_Stream7,
.rx_dma_stream = DMA1_Stream5,
.tx_dma_stream_id = 7,
.rx_dma_stream_id = 5,
.tx_dma_channel = DMA_Channel_1,
.rx_dma_channel = DMA_Channel_1,
.gpio_af_scl = GPIO_AF_I2C1,
.gpio_af_sda = GPIO_AF_I2C1
},
};
platform_i2c_driver_t platform_i2c_drivers[MICO_I2C_MAX];
const platform_uart_t platform_uart_peripherals[] =
{
[MICO_UART_1] =
{
.port = USART2,
.pin_tx = &platform_gpio_pins[STDIO_UART_TX],
.pin_rx = &platform_gpio_pins[STDIO_UART_RX],
.pin_cts = NULL,
.pin_rts = NULL,
.tx_dma_config =
{
.controller = DMA1,
.stream = DMA1_Stream6,
.channel = DMA_Channel_4,
.irq_vector = DMA1_Stream6_IRQn,
.complete_flags = DMA_HISR_TCIF6,
.error_flags = ( DMA_HISR_TEIF6 | DMA_HISR_FEIF6 ),
},
.rx_dma_config =
{
.controller = DMA1,
.stream = DMA1_Stream5,
.channel = DMA_Channel_4,
.irq_vector = DMA1_Stream5_IRQn,
.complete_flags = DMA_HISR_TCIF5,
.error_flags = ( DMA_HISR_TEIF5 | DMA_HISR_FEIF5 | DMA_HISR_DMEIF5 ),
},
},
[MICO_UART_2] =
{
.port = USART1,
.pin_tx = &platform_gpio_pins[MICO_GPIO_30],
.pin_rx = &platform_gpio_pins[MICO_GPIO_29],
.pin_cts = NULL,
.pin_rts = NULL,
.tx_dma_config =
{
.controller = DMA2,
.stream = DMA2_Stream7,
.channel = DMA_Channel_4,
.irq_vector = DMA2_Stream7_IRQn,
.complete_flags = DMA_HISR_TCIF7,
.error_flags = ( DMA_HISR_TEIF7 | DMA_HISR_FEIF7 ),
},
.rx_dma_config =
{
.controller = DMA2,
.stream = DMA2_Stream2,
.channel = DMA_Channel_4,
.irq_vector = DMA2_Stream2_IRQn,
.complete_flags = DMA_LISR_TCIF2,
.error_flags = ( DMA_LISR_TEIF2 | DMA_LISR_FEIF2 | DMA_LISR_DMEIF2 ),
},
},
};
const platform_adc_t platform_adc_peripherals[] =
{
[MICO_ADC_1] = { ADC1, ADC_Channel_0, RCC_APB2Periph_ADC1, 1, (platform_gpio_t*)&platform_gpio_pins[MICO_GPIO_24] },
[MICO_ADC_2] = { ADC1, ADC_Channel_1, RCC_APB2Periph_ADC1, 1, (platform_gpio_t*)&platform_gpio_pins[MICO_GPIO_23] },
[MICO_ADC_3] = { ADC1, ADC_Channel_4, RCC_APB2Periph_ADC1, 1, (platform_gpio_t*)&platform_gpio_pins[MICO_GPIO_22] },
};
至此,bootloader工程已移植完毕。
按照以上步骤移植完 Bootloader 工程,将程序编译下载进入开发板,然后打开串口调试工具,可以看到如下 log 信息,通过串口调试工具向开发板发送命令: 7,可以看到系统重启,有log信息输出,此时,bootloader移植成功,我们可以进入下一环节进行应用程序的移植。
(1)功能配置
在platform_config.h文件中声明相关引脚功能,如下:
/******************************************************
* EMW1062 Options
******************************************************/
/* Wi-Fi chip module */
#define EMW1062
/* GPIO pins are used to bootstrap Wi-Fi to SDIO or gSPI mode */
//#define MICO_WIFI_USE_GPIO_FOR_BOOTSTRAP_0
//#define MICO_WIFI_USE_GPIO_FOR_BOOTSTRAP_1
/* Wi-Fi GPIO0 pin is used for out-of-band interrupt */
#define MICO_WIFI_OOB_IRQ_GPIO_PIN ( 0 )
/* Wi-Fi power pin is present */
//#define MICO_USE_WIFI_POWER_PIN
/* Wi-Fi reset pin is present */
#define MICO_USE_WIFI_RESET_PIN
/* Wi-Fi 32K pin is present */
//#define MICO_USE_WIFI_32K_PIN
/* USE SDIO 1bit mode */
//#define SDIO_1_BIT
/* Wi-Fi power pin is active high */
//#define MICO_USE_WIFI_POWER_PIN_ACTIVE_HIGH
/* WLAN Powersave Clock Source
* The WLAN sleep clock can be driven from one of two sources:
* 1. MCO (MCU Clock Output) - default
* 2. WLAN 32K internal oscillator (30% inaccuracy)
*/
//#define MICO_USE_WIFI_32K_CLOCK_MCO
//#define MICO_USE_BUILTIN_RF_DRIVER
(2)引脚配置
打开platform.c文件,修改wifi_control_pins[]数组和wifi_spi_pins[]数组中相关引脚如下所示:
const platform_gpio_t wifi_control_pins[] =
{
[WIFI_PIN_RESET ] = { GPIOG, 2 },
};
const platform_gpio_t wifi_spi_pins[] =
{
[WIFI_PIN_SPI_IRQ ] = { GPIOG, 1 },
[WIFI_PIN_SPI_CS ] = { GPIOG, 3 },
[WIFI_PIN_SPI_CLK ] = { GPIOC, 10 },
[WIFI_PIN_SPI_MOSI] = { GPIOC, 12 },
[WIFI_PIN_SPI_MISO] = { GPIOC, 11 },
};
(3)驱动方式配置
wifi_spi_pins[]
数组内容,这个数组将被platform/MCU/STM32F2xx/EMW1062_driver/wlan)spi.c
中函数调用。配置 SPI DMA 接收中断的中断优先级:
//NVIC_SetPriority( DMA2_Stream3_IRQn, 3 ); /*WLAN SDIO DMA*/
NVIC_SetPriority( DMA1_Stream2_IRQn, 3 ); /* WLAN SPI DMA */
在platform.c文件中,配置 MicoShouldEnterMFGMode() 函数 和 MicoShouldEnterBootloader() 函数。
bool MicoShouldEnterMFGMode(void)
{
// if(MicoGpioInputGet((mico_gpio_t)BOOT_SEL)==false && MicoGpioInputGet((mico_gpio_t)MFG_SEL)==false)
// return true;
// else
return false;
}
bool MicoShouldEnterBootloader(void)
{
// if(MicoGpioInputGet((mico_gpio_t)BOOT_SEL)==false && MicoGpioInputGet((mico_gpio_t)MFG_SEL)==true)
// return true;
// else
return false;
}
以上配置方式是使用软件控制程序进入application应用程序中也可以打开以上两函数注释的内容通过外部引脚来控制模式,MFG_SEL引脚拉低,系统进入产测模式,BOOT_SEL引脚拉低,系统进入bootloader模式,当引脚均拉高,进入应用程序。
主要配置为串口中断的配置,本系统中,发送流通道USART1选为DMA2_Stream7,USART2选择DMA1_Stream6;接收流通道,USART1选择DMA2_Stream2,USART2船则DMA1_Stream5。具体配置如下所示。
MICO_RTOS_DEFINE_ISR( USART1_IRQHandler )
{
platform_uart_irq( &platform_uart_drivers[MICO_UART_2] );
}
MICO_RTOS_DEFINE_ISR( USART2_IRQHandler )
{
platform_uart_irq( &platform_uart_drivers[MICO_UART_1] );
}
MICO_RTOS_DEFINE_ISR( DMA1_Stream6_IRQHandler )
{
platform_uart_tx_dma_irq( &platform_uart_drivers[MICO_UART_1] );
}
MICO_RTOS_DEFINE_ISR( DMA2_Stream7_IRQHandler )
{
platform_uart_tx_dma_irq( &platform_uart_drivers[MICO_UART_2] );
}
MICO_RTOS_DEFINE_ISR( DMA1_Stream5_IRQHandler )
{
platform_uart_rx_dma_irq( &platform_uart_drivers[MICO_UART_1] );
}
MICO_RTOS_DEFINE_ISR( DMA2_Stream2_IRQHandler )
{
platform_uart_rx_dma_irq( &platform_uart_drivers[MICO_UART_2] );
}
(1)编译与下载
至此,我们已经完成了手把手的移值工作,只需将修改的板级支持包放到board目录下,通过mico-cube工具或MiCoder IDE对工程进行编译。
如在 git 命令行中,通过 mico-cube 工具命令: mico make application.wifi_uart@MK407 total download
, 完成编译和下载,log内容如下:
(2)结果验证
说明:Easylink是上海庆科开发的一款智能设备配网APP,请参考: Easylink SDK 下载安装使用。
上一篇:7.1 MiCO 总动员
下一篇:6.1 移植简介
版权所有 © 2017 - 2018 MXCHIP授权代理商 - 深圳市博易特智能科技有限公司 粤ICP备17063559号
服务热线:0755-23733662 Email:info@mxchip.cc