基于rt-thread 5.2.1 bsp/at/at32f437-start進行開發,記錄詳細過程,包括中間遇到的各種坑。
at32f437-start原理圖
自己設計的電路板主要換了一塊小封裝的同系列芯片, 目標是移植opENer。
1. 開發環境
env長時間不用,有點忘了。這次新下載了個2.0新版本。
軟件包列表更新,現在新加入的包很多,會出現和服務器不同步的情況。本次開發想用的opENer在iot里找不到,就需要更新。
軟件包更新和下載
pkgs --upgrade 命令更新軟件包列表
項目menuconfig選中相應的包后,需要下載。
pkgs --update 命令會自動更新/下載/刪除相關軟件包
2.項目配置
啟動ENV,進入bsp目錄,這兒選擇/bsp/at32/at32f437-start。menuconfig配置,項目硬件有uart,emac,pin,內部falsh,軟件包選了opENer。
從rt-thread 5.2.0起,硬件sdk包和以前版本稍有不同,需要通過on packages/peripheral libraries and drivers/HAL & SDK Drivers/AT32HAL & SDK Drivers中選擇對應的單片機型號。
保存配置,scons --update, 下載軟件包。scons --target==mdk5 生成項目文件。編譯項目,有幾個錯誤,提示找不到 fal_cfg.h文件。
因為選擇了fal,還需定義內部flash分區表,文件fal_cfg.h內容如下:
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_#include <rtthread.h>
#include <board.h>#include "drv_flash.h"
#include "fal.h"#ifdef __cplusplus
extern "C" {
#endifextern const struct fal_flash_dev at32_onchip_flash;
extern struct fal_flash_dev nor_flash0;/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \&at32_onchip_flash, \
}/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG/* partition table */
#define FAL_PART_TABLE \
{ \{FAL_PART_MAGIC_WROD, "app", "onchip_flash", 0, 1000 * 1024, 0}, \{FAL_PART_MAGIC_WROD, "param", "onchip_flash", 1000 * 1024, 6 * 1024, 0}, \
}#endif /* FAL_PART_HAS_TABLE_CFG */#ifdef __cplusplus
extern "C" {
#endif#endif /* _FAL_CFG_H_ */
AT32F435RG有1M flash, 把最后boot rom/user option前面的6K作為參數存儲區。
把fal_cfg.h文件存在bsp包中board/inc目錄下。重新編譯,完美通過!
執行?scons --dist?將配置好的項目生成獨立分發版本,只要把dist目錄復制出來就可以獨立開發了。需要注意的是,每次運行scons --dist命令,會把dist目錄里的內容清空,如有修改要做好備份!!!
完整命令為:scons --dist [--target=xxx] [--project-name="xxx"] [--project-path="xxx"]
3.修改硬件配置
由于項目用到了emac和uart1,uart3,管腳配置和at32f437-start的配置不一樣,有幾個地方還需要修改。
emac 采用RMII,節省資源。用到的引腳有PA1、PA2、PA7、PC1、PC4、PC5、PB11、PB12、PB13。phy芯片yt8512復位腳為PB1。
uart1使用PA9、PA10,uart3使用PC10、PC11。
除yt8512復位腳外,其它都在at32_msp.c文件中。
at32_msp.c中的修改部分。
#ifdef BSP_USING_UART3if(usart_x == USART3){crm_periph_clock_enable(CRM_USART3_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);gpio_init_struct.gpio_mode = GPIO_MODE_MUX;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_10 | GPIO_PINS_11;gpio_init(GPIOC, &gpio_init_struct);gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE10, GPIO_MUX_7);gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE11, GPIO_MUX_7);}
#endif#ifdef BSP_USING_EMAC
void at32_msp_emac_init(void *instance)
{gpio_init_type gpio_init_struct;crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);//lggpio_default_para_init(&gpio_init_struct);gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_mode = GPIO_MODE_MUX;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_1 | GPIO_PINS_2;gpio_init(GPIOA, &gpio_init_struct);gpio_init_struct.gpio_pins = GPIO_PINS_1;gpio_init(GPIOC, &gpio_init_struct);gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_11);gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE4, GPIO_MUX_11);gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE5, GPIO_MUX_11);gpio_init_struct.gpio_pins = GPIO_PINS_7;gpio_init(GPIOA, &gpio_init_struct);gpio_init_struct.gpio_pins = GPIO_PINS_4 | GPIO_PINS_5;gpio_init(GPIOC, &gpio_init_struct);gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_12 | GPIO_PINS_13;//lggpio_init(GPIOB, &gpio_init_struct);gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE1, GPIO_MUX_11);gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_11);gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE1, GPIO_MUX_11);gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE11, GPIO_MUX_11);//lggpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE12, GPIO_MUX_11);gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE13, GPIO_MUX_11);
}
#endif /* BSP_USING_EMAC */
phy芯片復位卻PB1,需要在drv_emac.c中phy_reset()函數中修改:
static void phy_reset(void)
{gpio_init_type gpio_init_struct;#if defined (SOC_SERIES_AT32F437) || defined (SOC_SERIES_AT32F457)crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);gpio_default_para_init(&gpio_init_struct);gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_1;gpio_init(GPIOB, &gpio_init_struct);gpio_bits_reset(GPIOB, GPIO_PINS_1);rt_thread_mdelay(2);gpio_bits_set(GPIOB, GPIO_PINS_1);
#endif
#if defined (SOC_SERIES_AT32F407)crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);gpio_default_para_init(&gpio_init_struct);gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_8;gpio_init(GPIOC, &gpio_init_struct);gpio_bits_reset(GPIOC, GPIO_PINS_8);rt_thread_mdelay(2);gpio_bits_set(GPIOC, GPIO_PINS_8);
#endifrt_thread_mdelay(2000);
}
最后還要在項目屬性頁(Device和C/C++)中把單片機型號改成AT32F437RG.
4. 遇到的問題
程序跑起來后,發現網絡有問題。phy_linkchange函數沒被調用,導致網絡不能用。經分析,是phy_monitor_thread_entry函數中的rt_thread_mdelay()導致線程掛起后,時間到了也沒被喚醒,后續代碼就沒有執行到。
static void phy_monitor_thread_entry(void *parameter)
{uint8_t detected_count = 0;while(phy_addr == 0xFF){/* phy search */rt_uint32_t i, temp;for (i = 0; i <= 0x1F; i++){emac_phy_register_read(i, PHY_BASIC_STATUS_REG, (uint16_t *)&temp);if (temp != 0xFFFF && temp != 0x00){phy_addr = i;break;}}detected_count++;//rt_thread_mdelay(1000);if (detected_count > 10){LOG_E("No PHY device was detected, please check hardware!");}}LOG_D("Found a phy, address:0x%02X", phy_addr);/* reset phy */LOG_D("RESET PHY!");emac_phy_register_write(phy_addr, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK);//rt_thread_mdelay(2000);emac_phy_register_write(phy_addr, PHY_BASIC_CONTROL_REG, PHY_AUTO_NEGOTIATION_MASK);phy_linkchange();
#ifdef PHY_USING_INTERRUPT_MODE/* configuration intterrupt pin */rt_pin_mode(PHY_INT_PIN, PIN_MODE_INPUT_PULLUP);rt_pin_attach_irq(PHY_INT_PIN, PIN_IRQ_MODE_FALLING, emac_phy_isr, (void *)"callbackargs");rt_pin_irq_enable(PHY_INT_PIN, PIN_IRQ_ENABLE);/* enable phy interrupt */emac_phy_register_write(phy_addr, PHY_INTERRUPT_MASK_REG, PHY_INT_MASK);
#if defined(PHY_INTERRUPT_CTRL_REG)emac_phy_register_write(phy_addr, PHY_INTERRUPT_CTRL_REG, PHY_INTERRUPT_EN);
#endif
#else /* PHY_USING_INTERRUPT_MODE */at32_emac_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);if (!at32_emac_device.poll_link_timer || rt_timer_start(at32_emac_device.poll_link_timer) != RT_EOK){LOG_E("Start link change detection timer failed");}
#endif /* PHY_USING_INTERRUPT_MODE */
}
把兩個rt_thread_mdelay調用注釋掉,正常。延時估計是為兼容不同的Phy芯片,對于YT8512不延時沒有問題。
至于為什么delay會讓線程沒法喚醒,還沒有仔細分析!!!可能細節還在其它地方。