灵动微电子

嵌入式工程师在开发产品中经常会用到MCU的片上UART和其它模块进行通信,为了在某些非正常的恶劣环境下能正常使用串口通信,可能需要对UART通信波特率进行自适应校准,在我们之前的微课堂中讲解过关于MM32通用MCU的UART串口通信方面的基础知识,这里我们增加基于灵动微电子MM32F013x 系列UART硬件自适应波特率的使用。

1、原理

UART硬件波特率自适应检测首个通信字节的位宽(1bit、2bit、4bit、8bit),检测前一个边沿和后一个边沿之间的位长,即检测前一个边沿为下降沿,后一个边沿为上升沿或前一个边沿为下降沿,后一个边沿为下降沿,可通过软件灵活配置。

本实例以串口工具作为上位机,MM32F013x的UART1作为下位机,MCU端初始化为非标准波特率9200,使能空闲中断及其他状态标志位,上位机切换不同的波特率,由于上位机和MCU端的波特率不同,可能出现通信失败的情况,启动UART硬件波特率自适应功能,即检测上位机发的首个字节位宽来识别上位机的波特率,MCU端通过硬件波特率自适应切换到对应的波特率,与上位机维持后续正常的通信。

如下图所示,以首字节0XF8为例,首字节位宽为4bit的原理说明:


2、程序配置

2.1 初始化MM32F013x UART1串口

从官网下载MM32F013x例程,这里我们在MM32F0133C7P的样例程序中添加注释并对代码修改。

#include "bsp_UART.h"
#include "led.h"
/*******************************************************************************
* 函数名称:void bsp_UART1_Init(u32 baudrate)
* 函数功能:初始化UART1 PA9/PA10分别作为UART1的TX/RX
* 输入参数:无
* 返回数值:无
******************************************************************************/
void bsp_UART1_Init(u32 baudrate)
{
    //GPIO初始化结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    //UART初始化结构体
    UART_InitTypeDef UART_InitStructure;    
    //NVIC初始化结构体
    NVIC_InitTypeDef NVIC_InitStructure;

    //使能UART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);        
    //使能GPIOA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  

    //开启GPIOA PA9复用于UART1_TX功能 
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);    
    //开启GPIOA PA10复用于UART1_RX功能 
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);   

    //UART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;     
    //配置GPIOA.9 速度为高速50MHz
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
    //配置GPIOA.9为复用推挽输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
    //根据GPIO结构体初始化UART1_TX GPIOA.9
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //UART1_RX GPIOA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;    
    //配置UART1_RX GPIOA.10为上拉输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    
    //根据GPIO结构体初始化UART1_RX GPIOA.10
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //串口波特率
    UART_InitStructure.UART_BaudRate = baudrate;    
    //字长为8位数据格式
    UART_InitStructure.UART_WordLength = UART_WordLength_8b;    
    //一位停止位
    UART_InitStructure.UART_StopBits = UART_StopBits_1;    
    //无奇偶校验位
    UART_InitStructure.UART_Parity = UART_Parity_No;    
    //无硬件数据流控
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;    
    //允许收发模式
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
    //根据UART结构体初始化串口UART1
    UART_Init(UART1, &UART_InitStructure);

    //硬件自动波特率检测第1个字节位的位宽前一个边沿为下降沿,后一个边沿为上升沿
    //___              _______
    //   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
    //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test

    UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);

    //接收数据中断、接收帧错误中断、自动波特率结束中断、自动波特率错误中断、空闲中断
    UART_ITConfig(UART1, UART_IT_RXIEN | UART_ICR_RXFERRCLR | UART_ICR_ABRENDCLR |\ UART_ICR_ABRERRCLR | UART_ICR_RXIDLE | UART_IT_ERR, ENABLE);
    //使能UART1
    UART_Cmd(UART1, ENABLE);

    //UART1 NVIC中断优先级设置
    NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
    //UART通道优先级0
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;          
    //IRQ通道使能
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        
    //根据指定的参数初始化NVIC寄存器
    NVIC_Init(&NVIC_InitStructure);    
}

2.2 编写MM32F013x UART1串口中断服务函数

继续在bsp_UART.c文件中编写MM32F013x UART1串口中断服务函数如下所示。

/*******************************************************************************
* 函数名称:void UART1_IRQHandler(void)
* 函数功能:串口1 UART1中断服务程序
* 输入参数:无
* 返回数值:无
*******************************************************************************/
//自动波特率帧错误标志
u8 Auto_BaudRate_FraErr_Flag = 0;
void UART1_IRQHandler(void)                    
{
    u8 Res;

    //UART1接收中断
    if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)  
    {
        //清UART1接收中断标志
        UART_ClearITPendingBit(UART1,UART_IT_RXIEN);            
        //读取UART1接收到的数据
        Res = UART_ReceiveData(UART1);        
        //UART1接收数据缓存起来,最大接收UART1_REC_LEN个字节 
        UART1_Rx_Buf[UART1_Rx_Cnt] = Res;        
        //UART1作接收缓存溢出判断,最大接收UART1_REC_LEN个字节
        if(UART1_Rx_Cnt < UART1_REC_LEN-1)
        {
            //还有数据要接收,接收计数变量自加
            UART1_Rx_Cnt++;
        }
        else
        {
            UART1_Rx_Cnt = 0;
        }
    }

    //帧错误中断标志位
    if(UART_GetITStatus(UART1, UART_IER_RXFERR) != RESET)
    {
        //自动波特率帧错误标志置1
        Auto_BaudRate_FraErr_Flag = 1;
        //清帧错误中断标志位
        UART_ClearITPendingBit(UART1,UART_IER_RXFERR);
    }

    //接收数据帧错误中断
    if(UART_GetITStatus(UART1, UART_ICR_RXFERRCLR) != RESET)
    {     
        UART_ClearITPendingBit(UART1,UART_ICR_RXFERRCLR);
    }

    //空闲中断硬件波特率自校准
    if(UART_GetITStatus(UART1, UART_ICR_RXIDLE) != RESET)
    {
        UART_ClearITPendingBit(UART1,UART_ICR_RXIDLE);

        //自动波特率帧错误标志
        if(Auto_BaudRate_FraErr_Flag == 1)
        {
            Auto_BaudRate_FraErr_Flag = 0;

    //----------------Check MM32F013x UART_AutoBaudRateHard----------
    //___              _______
    //   |_ _ _ _|1 x x x x|  = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
    //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test

        UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);    
        }
    }

    //自动波特率错误中断清除位
    if(UART_GetITStatus(UART1, UART_ICR_ABRERRCLR) != RESET)
    {      
        UART_ClearITPendingBit(UART1,UART_ICR_ABRERRCLR);  
    }

    //自动波特率结束中断清除位
    if(UART_GetITStatus(UART1, UART_ICR_ABRENDCLR) != RESET)
    {
        UART_ClearITPendingBit(UART1,UART_ICR_ABRENDCLR);
    }
}

2.3 MM32F013x UART1串口接收函数

在bsp_UART.h文件中宏定义UART1波特率、接收字节长度,变量声明以及UART1接收数据函数和发送数据函数声明。

 void UART1_Recv_Task(void)
{   
   //收到的数据原样返回到串口上位机
   UART_SendBytes(UART1,UART1_Rx_Buf, UART1_Rx_Cnt);
}

2.4 MM32F013x UART串口发送函数

在bsp_UART.c文件中编写MM32F013x UART1发送数据函数,发送单字节数据和发送多字节数据函数分别如下所示:

/*******************************************************************************
* 函数名称:void UART_SendByte(UART_TypeDef* UARTx,u8 dat)
* 函数功能:UART发送单字节数据
* 输入参数:UARTx:UART1/UART2;dat:待发送的数据
* 返回数值:无
*******************************************************************************/
void UART_SendByte(UART_TypeDef* UARTx,u8 dat)
{
    UART_SendData(UARTx, dat);

    while(!UART_GetFlagStatus(UARTx, UART_FLAG_TXEPT));
}

/*******************************************************************************
* 函数名称:void UART_SendBytes(UART_TypeDef* UARTx,u8* buf, u16 len)
* 函数功能:UART发送多字节数据
* 输入参数:UARTx:UART1/UART2;buf:待发送的数据;len:待发送数据的长度
* 返回数值:无
*******************************************************************************/
void UART_SendBytes(UART_TypeDef* UARTx,u8* buf, u16 len)
{
    while(len--)
    {
        UART_SendByte(UARTx,*buf++);       
    }
}

3、MM32F013x UART硬件 自适应波特率的功能演示

在main.c文件的main函数里初始化bsp_UART1_Init(9200)串口初始化函数,在while(1)大循环里调用测试UART1硬件自动波特率收发数据函数:UART1_Recv_Task();这里以检测UART1通信首字节为4bit宽为例,模式为前一个边沿为下降沿,后一个边沿为上升沿。

MCU端设置非标准波特率9200,我们通过上位机以不同的波特率发送F8进行硬件波特率自适应,自适应完成后UART1就切换到对应的波特率,MCU端收到数据后直接返回给上位机。


本文转自:灵动MM32MCU

围观 117

前面我们介绍了新出USB设备类型WebUSB,其中使用MM32 MCU实现WebUSB功能。既然可以通过网页与USB设备通信,那是否可以做别的功能,比如USB-DFU,当然是可以的,我们通过网页进行DFU功能,即WebDFU功能。因此我们本节我们讲解如何在MM32 MCU实现WebDFU功能。

DFU是使用USB作为微控制器和编程工具之间的通信信道,通常是PC。在DFU类规格书说明中指出所有的DFU命令、状态和数据交换都需要通过端点0进行。命令集和基本协议都定义好的,但是上层协议(数据格式,错误信息等)是客户相关的。也就是说DFU类并没有定义数据传输格式(s19,16进制,纯2进制等等)

由于一个设备同时进行DFU操作和正常运行功能活动是不现实的,因此在DFU操作期间必须停止正常运行活动,这就意味着设备必须改变运行模式——也就是说我们在进行固件更新时比如打印机不再是打印机了,它是一个flash存储器编程器。但是支持DFU的设备不能自主改变模式,这需要接受外部(人或者主机操作系统)的干预。

对于DFU功能,其完成实现固件升级可以分为4个不同阶段。

01、枚举

设备把自身的一些特性告知主机,嵌入在设备正常运行描述符中的一个DFU类接口描述符和相关的函数符能够完成这个目的,并且能够为通过控制管道的类专用的请求提供目标。

02、DFU枚举

主机和设备同意开始固件升级,主机向设备发出USB复位,设备发出第二个描述符集合,并且为传输阶段做准备,这会是相应设备的运行时驱动无效,并使得DFU驱动不受其他目标为该设备通信妨碍,重编程设备的固件。

03、传输

主机将固件映像传输给设备,功能描述符中的参数用于确保非易失性存储器编程的块大小和时序的正确性。状态请求用于保持主机和设备之间的同步。

04、显示

一旦设备向主机报告重新编程完成,主机箱设备则发送usb复位,设备重枚举并执行升级后的固件。为了保证只有DFU驱动加载,有必要的在枚举DFU描述符集合改变id-product字段。

本节我们来讲解如何在MM32 MCU实现WebDFU设备功能,对于MM32 MCU来说,实现WebDFU只需要在之前程序基础上修改添加部分代码即可,按照开源的WebDFU协议加入功能。

本次我们采用MM32L373 miniboard作为测试开发板。为了方便大家使用MM32 MCU的WebDFU设备功能,我们重新封装好全部代码,用户不需要自己配置那些麻烦的描述符等参数,只需要知道用之前的单一设备函数即可。

软件资源如下:

对于MM32 MCU的WebDFU,我们可以配置WebDFU的参数。

#define USBD_DFU_DNLOAD_ENABLE      1

#define USBD_DFU_UPLOAD_ENABLE      0

#define USBD_DFU_STRDESC              L"USB_DFU"

#define USBD_DFU_XFERBUF_SIZE        1024

#define USBD_WEBUSB_VENDOR_CODE   0x21

#define USBD_WEBUSB_BASE_LANDING_URL "devanlai.github.io/webdfu/dfu-util/?vid="

#define USBD_WEBUSB_LANDING_URL     CONCAT_MACRO_TO_STRING(USBD_WEBUSB_BASE_LANDING_URL, USBD_DEVDESC_IDVENDOR)

#define USBD_WEBUSB_ORIGIN_URL      "devanlai.github.io/"

#define USBD_WEBUSB_IF_NUM          USBD_DFU_IF_NUM

参数设置如上。当进行DFU升级时候,可以看到电脑上显示的设备名称为USB_DFU,就是配置的USBD_DFU_STRDESC参数。

在使用MM32 WebDFU功能之前先调用USB初始化函数来初始化USB协议栈。

int main(void)

{

// USB Device Initialization and connect

usbd_init();

usbd_connect(__TRUE);

while (!usbd_configured())     // Wait for USB Device to configure

{

}

while (1)

{     

……

}

}

然后依然和之前一样只是在WebUSB基础上修改添加WebDFU相关参数函数接口即可,代码如下:

//DFU初始化

void usbd_dfu_init(void)

{

DFU_Reset();

current_write_addr = 0;

}

//USB DFU开始升级

BOOL USBD_DFU_StartUpgrade(void) {

error_t err = flash_manager_init(target_device);

current_write_addr = target_device.flash_start;

switch (err) {

case ERROR_SUCCESS:

initialized = true;

break;

case ERROR_RESET:

case ERROR_ALGO_DL:

case ERROR_ALGO_DATA_SEQ:

case ERROR_INIT:

case ERROR_SECURITY_BITS:

case ERROR_UNLOCK:

DFU_SetStatus(DFU_STATUS_ERR_PROG);

break;

case ERROR_ERASE_SECTOR:

case ERROR_ERASE_ALL:

DFU_SetStatus(DFU_STATUS_ERR_ERASE);

break;

case ERROR_WRITE:

DFU_SetStatus(DFU_STATUS_ERR_WRITE);

break;

case ERROR_FAILURE:

case ERROR_INTERNAL:

default:

DFU_SetStatus(DFU_STATUS_ERR_UNKNOWN);

break;

}



return (err == ERROR_SUCCESS) ? (__TRUE) : (__FALSE);

}

//复位目标

static bool reset_target(bool error_condition) {

current_write_addr = 0;

if (initialized) {

error_t err = flash_manager_uninit();

switch (err) {

case ERROR_SUCCESS:

if (config_get_auto_rst()) {

// Target is reset and run by the uninit

} else if (!error_condition) {

// Reset and run the target at the end of a successful upgrade

target_set_state(RESET_RUN);

}

break;

case ERROR_RESET:

case ERROR_ALGO_DL:

case ERROR_ALGO_DATA_SEQ:

case ERROR_INIT:

case ERROR_SECURITY_BITS:

case ERROR_UNLOCK:

DFU_SetStatus(DFU_STATUS_ERR_PROG);

break;

case ERROR_ERASE_SECTOR:

case ERROR_ERASE_ALL:

DFU_SetStatus(DFU_STATUS_ERR_ERASE);

break;

case ERROR_WRITE:

DFU_SetStatus(DFU_STATUS_ERR_WRITE);

break;

case ERROR_FAILURE:

case ERROR_INTERNAL:

default:

DFU_SetStatus(DFU_STATUS_ERR_UNKNOWN);

break;

}

initialized = false;

return (err == ERROR_SUCCESS);

}



return true;

}

//USB DFU结束升级

BOOL USBD_DFU_FinishUpgrade(void) {

return reset_target(false) ? (__TRUE) : (__FALSE);

}

//USB DFU写数据

BOOL USBD_DFU_WriteBlock(const U8 *buffer, U16 blockSize) {

error_t err = flash_manager_data(current_write_addr, (U8*)buffer, blockSize);

switch (err) {

case ERROR_SUCCESS:

current_write_addr += blockSize;

break;

case ERROR_RESET:

case ERROR_ALGO_DL:

case ERROR_ALGO_DATA_SEQ:

case ERROR_INIT:

case ERROR_SECURITY_BITS:

case ERROR_UNLOCK:

DFU_SetStatus(DFU_STATUS_ERR_PROG);

break;

case ERROR_ERASE_SECTOR:

case ERROR_ERASE_ALL:

DFU_SetStatus(DFU_STATUS_ERR_ERASE);

break;

case ERROR_WRITE:

DFU_SetStatus(DFU_STATUS_ERR_WRITE);

break;

case ERROR_FAILURE:

case ERROR_INTERNAL:

default:

DFU_SetStatus(DFU_STATUS_ERR_UNKNOWN);

break;

}

return (err == ERROR_SUCCESS);

}

这样我们就完成MM32 MCU的WebDFU功能,将程序下载到板子中,USB插上电脑,电脑上会枚举出USB DFU。在USB DFU枚举成功后,我们需要检查是否真的可以被WebDFU网页识别。

打开https://devanlai.github.io/webdfu/dfu-util/通过该网页检测WebDFU工作状态,网页如下图所示:


通过点击Connect就可以像之前WebUSB设备一样弹出窗口选择我们的USB DFU设备,然后就可以在Vendor ID(hex)窗口看到序列号。可以通过网页上的Detach DFU和Download以及Upload进行DFU升级动作。

以上就是MM32 MCU USB的WebDFU功能,具体的WebDFU协议过程想详细了解看dapboot,大家可以自由发挥修改底层和上层的代码实现自己的WebDFU网页端和设备端。

本文转自:灵动MM32MCU

围观 234

灵动微MM32F103系列产品使用高性能内核M3的 32 位微控制器,典型工作频率可达144MHZ,内置高速存储器,丰富的增强型 I/O 端口和外设连接到外部总线。提供5种封装形式,包括 LQFP100、LQFP64、LQFP48、LQFP32 和 QFN32 共 5 种封装形式。根据不同的封装形式,器件中的外设配置不尽相同。该产品适合使用在电机驱动和应用控制,医疗和手持设备,工业应用以及警报系统等。下面英尚微代理商解答关于MM32F103产品中的一些常见问题。

SPI

1 、SPI 支持哪几种模式

按传输方向分
1) 全双工模式,同时收发数据,同时使能 TX 和 RX;
2) 半双工,在不同时间段进行读写,ENABLE TX 时 DISABLE RX,ENABLE RX 时 DISABLE TX;

按采样时序分
1) 模式 0,空闲时时钟为低,第一个时钟沿采样;
2) 模式 1,空闲时时钟为低,第二个时钟沿采样;
3) 模式 2,空闲时时钟为高,第一个时钟沿采样;
4) 模式 3,空闲时时钟为高,第二个时钟沿采样;

2 、SPI 主机通信不正常有哪些原因

常见原因:
1) 配置不正确,表现为无时钟输出;
2) 模式配置不正确,表现为采样点与预期不一致(SPI_CCTL bit0 = 0 为第二个时钟沿采样);
3) 速度配置过快,表现为波形异常;
4) 数据位数配置与 device 不一致,表现为 CLK 个数不对.
5) CS 信号不正确,表现为 CS 信号与 device 时序不对应;

Vbat 的电源接入有什么要求;
如果在应用中没有外部电池, 建议 VBAT 在外部通过一个 100nF 的陶瓷电容与 VDD 相连. 如外接为电池,为保证不损坏,建议在外部 VBAT 和电源之间连接一个低压降二极管。如无外接电池,即使不用 RTC 功能,也需要给 VBAT 供电;

KEIL 例程编译失败可能导致的原因

常见原因:
1) 没有安装 keil4 的兼容包,软件名称为:MDKCM516_legacySupportMDK4(出问题最多)
2) 移动了 keil 工程文件,导致无法找到相对路径的文件
3) 程序太大,超过 FLASH 或者SRAM容量

解决办法
针对 1 和 2 的问题,将 BOOT0 和 BOOT1 接到高电平,复位或者重新上电一下,然后再读 ID。若能读到 ID,则在此模式下擦除程序,然后再将 BOOT0 和 BOOT1 接低电平,这时候 ID 就能读到了。

KEIL 程序编译通过了,可是下载程序失败

常见原因:
1) 硬件电路没有接好,查看 debug 工具是否连接上板子中的 JTAG 或者 SWD,能否读到芯片IDCODE。
2) 若是 Debug 工具能读到芯片 ID,但是无法下载,原因是没有选择 Description 型号,具体配置选择如下图所示。

灵动微MM32F103单片机常见问题解答

外部高速时钟接法

外部无源晶振电路如下图所示,晶振两脚接约 22pf 电容,并上 1M 反馈电阻。因芯片内部没有集成反馈电阻,为保证 XTAL 起振,必须接 1M 欧姆电阻;

灵动微MM32F103单片机常见问题解答

外部时钟异常常见原因
运行程序通常用到外部高速时钟做系统时钟源,有时候在调试中会遇到系统时钟异常导致程序停止运行,以下列出几点可能的原因:
1) 外部晶振未加反馈电阻,导致外部无稳定时钟输入;
2) 外部晶振范围 8~24MHz;
3) 晶振与芯片引脚间断路;
4) 晶振质量问题导致,不正常起振;
5) 芯片系统时钟配置过程错误等等

本文来源:英尚微电子,转载此文目的在于传递更多信息,版权归原作者所有。

围观 303

一般简单的嵌入式系统软件的编程思路是下面这样的:

main

{

{任务1};

{任务2};

{任务3};

.......

{任务N};

}



isr_server

{

{处理中断};

}

这是嵌入式工程师编程的一般思路,对于一个简单的系统当然是够用了,但在这样的系统中每个任务的实时性是很差的,比如如果“任务1”用于用户输入的检测,当用户输入时,如果程序正在执行其他的任务进程,那么这次用户输入将失效,用户的体验是“这个按键不灵敏,这个机器很慢”。

而我们如果把所有任务都放到中断里去处理,虽然改善了实时性,却会导致另外一个问题:一个任务在处理的时候有可能会引发其它的中断丢失。这个后果有时候比“慢一点”更加严重和恶劣!又比如任务2是一个只需要1s钟处理一次的任务,那么显然任务2会白白浪费CPU的时间。

这时,我们可能需要改进我们的编程思路,一般我们会尝试采用“时间片”的方式。这时候软件结构会变成下面的方式:

main

{

{如果任务1的时间片到了则执行任务1};

{如果任务2的时间片到了则执行任务2};

.......

{如果任务N的时间片到了则执行任务N};

}

timer_isr_server

{

{判断每个任务的时间片是否到来,并进行标记};

}

isr_server

{

{处理中断};

}

我们可以看到,这种改进后的思路,使得任务的执行时间得到控制,任务只在自己的时间片到来后,才会去执行。但你可以发现,这种方式仍然不能彻底解决“实时性”的问题,因为某个任务的时间片到来后,也不能立即就执行,MCU必须等到当前任务的时间片用完,并且后面的任务时间片还没有来,MCU才有机会获得“执行时间”。

这时候我们需要继续改进思路。为了使得某个任务的时间片到来以后能立即执行,我们需要在时钟中断里判断完时间片后,改变程序的返回位置,让程序不返回到刚刚被打断的位置,而从最新获得了时间片的任务处开始执行,这样就彻底解决了任务的实时问题。

我们在这个思路上进行改进。在每次进入时钟中断前,MCU保存当前状态和当前任务的关键数据,然后进入时钟中断进行时间片处理。如果这时判断有新的更紧急的任务的时间片到来,则执行任务切换,恢复这个更紧急的任务的现场,然后返回中断开始执行这个更紧急的任务。

到这里,我们终于知道了操作系统的作用了。事实上,操作系统的用处远不止帮你完成这个“任务时间片的处理”,操作系统还能帮你处理各种超时,进行内存管理,完成任务间的通信等。有了操作系统,程序的层次也更加清晰,给系统添加功能也更方便,这一切在大型项目中越发的明显!

近年来,物联网IOT概念广为普及,物联网市场发展迅猛,嵌入式设备的联网已然成为趋势。终端联网使得软件复杂性大幅增加,传统的 RTOS 内核已经越来越难满足市场的需求。正是在这种情况下,物联网操作系统(IoT OS)的概念应运而生。

物联网操作系统是指以操作系统内核(可以是 RTOS、Linux 等)为基础,包括文件系统、图形库等较为完整的中间件组件,具备低功耗、安全、通信协议支持和云端连接能力的软件平台。

灵动微电子MM32系列MCU获得了AMetal、RT-Thread、Alios、Liteos、mbed、FreeRTOS等众多操作系统官方鼎立支持,面对越来越多的MM32 MCU用户对于操作系统的使用需求,灵动微电子官方微信公众号将在接下来的微课堂针对各家OS进行详细的移植及应用讲解,欢迎广大爱好者关注并指导!

参考链接:

AMetal:
https://github.com/zlgopen/ametal
https://gitee.com/zlgopen/ametal

RT-Thread:
https://github.com/RT-Thread/rt-thread/tree/master/bsp/mm32l3xx

Alios:
https://certification.iot.aliyun.com/open/#/awardview?key=C39AEF360BC5F5...

Liteos:
https://gitee.com/LiteOS

来源:灵动微电子

围观 39

WebUSB功能

在前面几个章节我们介绍了MM32 MCU的各种常用的USB功能,而随着物联网的发展,有时候希望我们直接可以通过网页访问USB设备,于是出现了一种新的usb使用类型即WebUSB,通过让MCU USB实现WebUSB功能,就可以直接与网页通信,因此我们本节我们讲解MM32 MCU的WebUSB功能。

对于WebUSB来说,其是由Reilly Grant和Ken Rockot开发的,它已经被推入W3C WICG,以求建立一个能够被浏览器制造商引用的平台。WebUSB是一个Javascript API,可以允许网页访问已连接的USB设备,这里的USB设备是指系统和工业的USB设备。通过WebUSB API,我们可以让USB设备,比如键盘、鼠标、3D打印机和硬件驱动连接到物联网,甚至在Web页面上进行定位。这一产品的目的,是为了帮助硬件制造商将他们的USB设备实现跨平台通用(包括Web),此后不需要为特定的平台写本地驱动或者SDK。除了控制硬件,WebUSB也可以通过Web页面安装固件升级或者执行其他重要任务。然而,这个草拟版本的API并不能传输文件。

当然,目前WebUSB现在只是个草拟版本,还没有正式采用W3C标准。其开发工作仍然在进展之中,但是我们现在还是可以在Github上看到完整的WebUSB代码库(https://github.com/wicg/webusb)。

WebUSB原理

当USB设备插入主机时,浏览器会读取设备发送的描述符,然后将其储存在内部USB设备储存器中。此过程由Chrome的浏览器内核Blink处理。日志可以在chrome://device-log(GET参数“refresh = 1”非常有用)中查看。

根据规范要求,设备可以在其二进制对象存储中的平台描述符中明确地声明对WebUSB的支持。

图1 WebUSB功能描述符

浏览器将每个USB设备存储在自己的设备存储器中。WebUSB的可访问性由本机驱动程序支持所决定。在Windows上,我们可以通过浏览器访问由WinUSB驱动程序处理的每个USB设备。其他的诸如大容量存储设备,网络摄像头或HID等就无法通过网络访问了,因为它们具有处理这些设备的专用驱动程序。

本节我们来讲解如何在MM32 MCU实现WebUSB设备功能,对于MM32 MCU来说,实现WebUSB只需要在之前程序基础上修改添加部分代码即可。

本次我们采用MM32L373 miniboard作为测试开发板。为了方便大家使用MM32 MCU的WebUSB设备功能,我们已经封装好全部代码,用户不需要自己配置那些麻烦的描述符等参数,只需要知道用之前的单一设备函数即可。

软件资源如下:

对于MM32 MCU的WebUSB,我们可以配置WebUSB的参数来让网页识别设备。

#define USBD_WEBUSB_STRDESC         L"WebUSB: MM32"
//     WebUSB support
#define USBD_WEBUSB_ENABLE          WEBUSB_INTERFACE
#define USBD_WEBUSB_VENDOR_CODE     0x21
#define USBD_WEBUSB_LANDING_URL   "os.mbed.com/webusb/landing-page/?bid="
#define USBD_WEBUSB_ORIGIN_URL      "os.mbed.com/"

参数设置如上可以看到电脑上显示的设备名称WebUSB:MM32,如下:

图2 WebUSB枚举列表

在使用MM32 WebUSB功能之前先调用USB初始化函数来初始化USB协议栈。

int main(void)
{
// USB Device Initialization and connect
usbd_init();
usbd_connect(__TRUE);
while (!usbd_configured())   // Wait for USB Device to configure
{
}
while (1)
{      
……
}
}

然后依然和之前一样只是在WINUSB基础上添加WebUSB相关参数函数接口即可,代码如下:

#if (USBD_WEBUSB_ENABLE)
usbd_webusb_if_num = if_num++;   
desc_ptr += webusb_desc_fill(&USBD_ConfigDescriptor[desc_ptr], &USBD_ConfigDescriptor_HS[desc_ptr], usbd_webusb_if_num);
#endif
#if (USBD_WEBUSB_ENABLE)
static U16 webusb_desc_fill(U8 * config_desc, U8 * config_desc_hs, U8 if_num) {
U8 * pD = 0;
const U8 webusb_desc[] = {
WEBUSB_DESC
};
pD = config_desc;
memcpy(pD, webusb_desc, sizeof(webusb_desc));
 ((USB_INTERFACE_DESCRIPTOR *)pD)->bInterfaceNumber = if_num;
#if (USBD_HS_ENABLE == 1)
pD = config_desc_hs;
memcpy(pD, webusb_desc, sizeof(webusb_desc));
 ((USB_INTERFACE_DESCRIPTOR *)pD)->bInterfaceNumber = if_num;
#endif
#if (USBD_WINUSB_ENABLE)
pD = USBD_WinUSBDescriptorSetDescriptor + WINUSB_DESCRIPTOR_SET_HEADER_SIZE;
 ((WINUSB_FUNCTION_SUBSET_HEADER*)pD)->bFirstInterface = if_num;
#else
#error "WEBUSB requires WINUSB!"
#endif
return sizeof(webusb_desc); 
}
#endif

这样我们就完成MM32 MCU的WebUSB功能,将程序下载到板子中,USB插上电脑,电脑上会枚举出WebUSB。在WebUSB枚举成功后,我们需要检查是否真的可以被网页识别。找了一个静态网页,通过该网页检测WebUSB工作状态。

图3 测试网页

要测试设备是否支持,请单击“选择设备”按钮打开权限提示。此提示将列出所有可用的USB设备。通过选择所需的设备并单击“连接”,工具将打开设备,并遍历每个可用的界面,并尝试声明。结果记录在页面底部的表格中。被声明的interfaces列显示可以声明的接口编号,我们点击choose A Device。

图4 WebUSB连接页面

从图上可以看到网页找到了MM32实现的WebUSB设备,以上就是MM32 MCU USB的WebUSB功能。

在下一张章节将会继续带来WebUSB DFU升级教程,后续将对USB的相关功能程序进行单独的封装打包,正式在MM32 MCU的官方发布,方便大家参考使用,敬请期待。

本文转自:灵动MM32MCU

围观 1501

近日,上海灵动微电子股份有限公司(以下简称“灵动微电子”)与上海华虹宏力半导体制造有限公司(以下简称“华虹宏力”)、通富微电子股份有限公司(以下简称“通富微电”)基于各自的技术实力和行业优势,优势互补,各展所长,共同助力智能硬件,特别是MCU主控芯片的国产化产业链发展。

灵动微电子是一家致力于提供通用32位MCU产品及解决方案的供应商,凭借对具体细分市场的深入思考和耕耘、对客户的良好服务、对工程的投入以及对品质的要求,2019年灵动微电子获得了跨越式的增长,营业收入破亿元,成为本土32位MCU的龙头之一。而在客户开拓方面,灵动微电子的MCU已进入以小米为代表的多家国内外一线品牌,大客户的长期支持也为灵动的持续高速发展提供保障。

为了满足品牌客户对品质、产能、技术和服务等更高标准要求,灵动微电子将不断加强与华虹宏力、通富微电的合作,借力5G+AI+IoT带来的巨大机会,携手共同推进智能硬件芯片发展。

小米产业基金合伙人潘九堂表示:“5G+AI+IoT将是下一代超级互联网,它将带动所有电子产品的智能化升级,包括更智能化的人机交互、处理、连网和AI等功能,这都需要更高性能、更高品质和更低功耗的MCU来承载,可以说MCU是下一代超级互联网的基础器件之一,必将迎来高速发展。小米作为全球领先的消费级物联网平台,目前IoT平台已连接的IoT设备数已经突破2.13亿,非常欢迎和灵动微电子这种坚持在技术和市场方面长期投入的优秀MCU公司合作,为全球用户带来更好的产品和服务”。

华虹宏力战略、市场与发展部总监胡湘俊表示:“华虹宏力拥有多种业界领先的嵌入式非易失性存储器技术,为客户提供精良的工艺和专业优质的服务,可实现高、中、低端MCU产品全覆盖。公司立足‘8+12’战略布局,将8英寸特色工艺优势延伸至12英寸,满足包括5G和物联网在内的各种多元化应用。公司将不断创新与扩展MCU代工组合,提供超低漏电、超低功耗、高速MCU代工解决方案,以更先进的技术和更充足的产能为全球客户服务。”

通富微电业务中心姜峰总表示:“作为国内领先的集成电路专业封测龙头企业,通富微电以其可靠的品质管理、及时的交货期、优良的综合服务,确保相关产品大规模量产并顺利实现国产化。此次与灵动微电子、华虹宏力合作,有利于实现产业链贯通,优势互补,资源共享,更好的为客户提供一站式服务,从而全面提升我国MCU产业水平,提升行业竞争力,也会对本公司销售收入和利润产生积极的影响,对提升本公司综合竞争力有重要而积极的意义。”

灵动微电子MCU产品事业部市场总监黄致恺表示:“灵动微电子是中国本土领先的通用32位MCU产品及解决方案供应商,灵动目前基于arm Cortex-M系列内核已开发了F/L/SPIN/W/P五大系列,200多个型号的MM32 MCU产品,并广泛应用于汽车电子、工业、电机、家电、医疗、消费玩具、手机平板周边、显示及交互等领域。灵动非常高兴能与华虹宏力、通富微电这样的优秀企业合作,共同推进国内MCU的成长。”

灵动微电子通过上下游产业链的友好合作,满足客户对MCU产品日益增长的需求,打通智能产品从芯片概念设计直达终端客户的国产本土化产业链,成为国内MCU市场一支新兴力量。

关于灵动微电子

灵动微电子成立于2011年,是中国本土领先的通用32位MCU产品及解决方案供应商。公司基于arm Cortex-M系列内核开发的MM32 MCU产品拥有F/L/SPIN/W/P五大系列,200多个型号,累计交付近亿颗,在本土通用32位MCU公司中位居前列。MM32 MCU被广泛应用于汽车电子、工业、电机、家电、医疗、消费玩具、手机平板周边、显示及交互等领域,每年都有数千万件配备了灵动微电子MM32 MCU的优秀产品交付到客户手中。迄今为止,灵动微电子是本土仅有的同时获得了ARM-KEIL、IAR、SEGGER国际权威组织官方支持的本土MCU公司,是为数不多的建立了独立、完善的生态体系的通用MCU公司,可以为客户提供从优异芯片产品到核心算法、从完备参考设计方案到整机开发的全方位支持,真正为中国电子信息产业提供底层技术驱动和支持。

来源: 灵动MM32MC

围观 35

号外!AMetal平台迎来新的成员,灵动微电子MM32系列MCU将陆续入驻AMetal平台,MM32L373、MM32L073系列芯片基于AMetal平台的SDK已在github和码云开源发布,后续将支持MM32全系列MCU,欢迎您的试用。

灵动微电子成立于2011年,是中国本土领先的通用32位MCU产品及解决方案供应商。公司基于Arm Cortex-M系列内核开发的MM32 MCU产品拥有F/L/SPIN/W/P五大系列,200多个型号,累计交付近亿颗,在本土通用32位MCU公司中位居前列。MM32 MCU被广泛应用于汽车电子、工业、电机、家电、医疗、消费玩具、手机平板周边、显示及交互等领域,每年都有数千万件配备了灵动微电子MM32 MCU的优秀产品交付到客户手中。

灵动微电子同时获得了ARM-KEIL、IAR、SEGGER等国际权威组织官方支持,是为数不多的建立了独立、完善的生态体系的本土通用MCU公司,可以为客户提供从优异芯片产品到核心算法、从完备参考设计方案到整机开发的全方位支持,真正为中国电子信息产业提供底层技术驱动和支持。

立功科技与灵动微电子强强联合,开启MM32 MCU全面适配AMetal,目前MM32L373、MM32L073系列芯片基于AMetal平台的SDK已在github和码云率先开源发布,欢迎您的试用,MM32产品路线发展规划如下图所示:

1

1、立功科技基于AMetal平台为灵动微电子MM32 MCU适配了底层驱动及标准接口,用户使用时,可以完全脱离用户手册及繁杂的寄存器操作,直接调用AMetal提供的接口函数,软件开发效率将大大提高。

1

2、AMetal 提供高效、功能完善的服务组件,主要包括USB、Lora、Modbus、链表、环形缓冲区;以及常用器件的驱动,如:74HC595、LM75、EP24Cxx、MX25xx、DS1302 等;应用程序需要的一切,都可以提供,利用平台提供的软件组件,用户可以省去大量的软件编写及测试时间,专注于应用代码的开发,将极大提高研发效率,尽快走向量产之路。

1

3、为简化不同厂商、型号之间MCU外设的使用方法,使应用程序不与具体的硬件绑定,进而实现“跨平台复用”,AMetal提供了一套通用接口。通用接口只与“抽象的”的功能相关,而与“具体的”硬件无关。若应用程序基于通用接口编写,无需关心任何底层细节,直接使用AMetal提供的标准接口实现相应功能。在更换底层MCU时,应用程序无需作任何修改,即可无缝迁移,大大提高效率。

1

基于AMetal平台开发的优势:

  • 您将获得丰富的软件组件,瞬间提高项目研发起点;

  • 您将省去阅读数千页手册的时间,更专注应用和算法的开发;

  • 您还将拥有一个强大的软件研发团队,随时为您提供技术支持;

  • 选择一个不断成长壮大的开源平台,更将成为您量产征途的一把利剑。

源码获取地址

github: https://github.com/zlgopen/ametal 

码云:   https://gitee.com/zlgopen/ametal 

欢迎您的试用。

1

来源: 灵动MM32MCU

围观 51

最近有部分刚接触MM32 MCU的用户朋友们碰到了MCU无法进行下载的情况,然后跟我们反馈芯片有问题,最后经过技术工程师跟进,其实都是用户程序使用错误或者操作不规范等原因造成的,并非芯片有问题,小编表示很无奈很无辜(T_T)。如果大家有碰到这种情况,请不要着急,我们今天这篇文章专门来讲解如何解决烧写失败的情况及有可能出现该类问题的原因。

MM32无法进行烧写原因有多种情况,我们从硬件和软件两个方面分析:

硬件原因:

1、使用的调试器不支持调试下载MM32 MCU,IAR/KEIL上仿真器选择/配置不正确,MM32 MCU已经获得Segger官方认证。在Segger官网J-Link驱动6.40以上版本支持MM32 MCU系列,MM32 MCU支持如MM32-Link、U-link、J-Link、DAP-Link等使用SWD/JTAG(M3)等方式对内核、外设、FLASH进行访问。

2、MM32 MCU最小系统不完整,复位电路设计错误、MCU供电不正常等也会出现无法识别设备Device等情况。MM32 MCU支持宽电压2.0-5.5v供电,在用户自己设计产品PCB时,建议用户预留VCC、SWDIO、SWCLK、GND、NRST五线下载口方式。大家在进行电路设计时请参考我们demo板进行设计,demo板资料在我们官网链接如下:http://www.mm32mcu.com/getfile.aspx?id=386

3、SWD的两个引脚PA13、PA14引脚虚焊,外部硬件有上拉或下拉,与调试器连接不正确或未连通等情况。

软件原因:

1、程序下载错误,MM32MCU有F、L、SPIN、W、P五大系列,对于不同的MCU我们有不同的库、启动文件与例程,大家下载程序前请查看自己MCU版本型号是否与要下载的程序对应,例如MM3F031C6T6分q版和n版,两个型号由于时钟域配置不同,程序不能直接共用。MM32MCU选型表料在官网链接如下:http://www.mm32mcu.com/getfile.aspx?id=955,库和例程等资料在官网链接如下:http://www.mm32mcu.com/download.aspx?cid=2542

2、MCU处于读/写保护状态,当MCU处于读保护状态时,FLASH空间处于写保护状态,此时无法使用SWD协议对内核、外设、FLASH进行访问,无法进行下载调试。

3、MCU处于低功耗状态,当MCU处于不同模式低功耗状态时,MCU的外设区域会处于断电状态,调试器识别MCU处于断电状态,无法进行下载调试。

4、SWD的两个引脚PA13、PA14被复用为其他功能或通用IO,PA13、PA14被配置为其他工作模式,此时PA13、PA14无法正常工作在SWD模式,调试器无法通过SWD协议进行下载调试。

5、程序下载过程中出错,由于下载速度和调试器版本特性等原因造成下载过程中出错,导致MCU进入HardFault状态(程序跑飞),此时无法进行下载调试。

下面以J-Link为例,列举两种具体表现形式与解决方案:

一、表现形式:下载报错No Cortex-M SW Device Found。此时调试器未识别到MCU(在keil中无法读到芯片ID),无法下载程序。


可能原因:硬件问题:1、2、3;软件问题:1、2、3、4、5;

解决方式:先检查硬件,确保使用的调试器支持仿真调试MM32MCU,查看MM32MCU最小系统是否完整、复位电路(建议电阻上拉100k,接100nF电容到地)与MCU供电是否正常,测量PA13、PA14引脚是否虚焊,有无上拉或下拉,确认与调试器连接正确并联通。

确认硬件无问题后,仿真方式选择SWD、速度设置建议在1M-10M以内,方法1:NRST脚拉低(按住复位键或短接复位电容,此时在KEIL中可读到ID),然后在IAR/KEIL中擦除程序(在keil的flash工具栏下的Erase操作),在IAR/KEIL出现进度条时释放NRST下拉电平,将芯片程序擦除后,重新上电就可以对MCU进行下载调试;方法2:将BOOT0接高,重新断电上电让MCU从SRAM启动,然后将芯片程序擦除,将BOOT0接低,重新上电就可以对MCU进行下载调试。

二、表现形式:下载报错Error:Flash Download failed – “Cortex - M0”。此时调试器能识别到MCU(在keil中可以读到芯片ID),可以擦除程序,无法下载程序。


可能原因:软件问题:1、5;

解决方式:方法1:调整下载速度,速度设置建议在1M-10M以内,可多调节几个速度试下,Download Fuction选择Erase Full Chip;方法2:如果还是无法下载则进行恢复出厂设置操作,资料在官网链接如下:http://www.mm32mcu.com/getfile.aspx?id=772

下面介绍使用MM32-Link的解决方案:

如果手上有MM32-Link则可以直接使用MM32-Link+Program来进行恢复操作,MM32-Link支持包与文档资料链接如下:http://www.mm32mcu.com/getfile.aspx?id=963

使用MM32-Link解决方式操作如下:

1、参照文档连接MM32-Link与MM32MCU,建议使用五线下载方式:VCC、SWDIO、SWCLK、GND、NRST。

2、打开MM32-Link Program,新建workspace,根据芯片型号新建project。

3、确保ICP Program模式下,左下角MM32-Link处圆点为绿色(不为绿色时检查MM32-Link是否连接电脑并正确识别设备,为黄色时双击左下角圆点),芯片连接处圆点为黄色或绿色(为灰色时检查硬件连接并手动对芯片进行一次复位操作,拉低NRST引脚)。

4、点击Erase Chip按钮,等待擦除完成即可重新下载。


以上方式下载均在我们官网例程上进行测试,如果有使用自己新建工程无法下载的情况,请检查自己工程配置与IDE版本,建议使用IAR版本在7.4以上、KEIL版本在5.13及以上,IAR与KEIL上新建MM32 MCU工程方式请参照官网应用文档,在KEIL下新建MM32 MCU工程官网链接如下:http://www.mm32mcu.com/getfile.aspx?id=341,在IAR下新建MM32 MCU工程官网链接如下:http://www.mm32mcu.com/getfile.aspx?id=396

本文转自: 灵动微电MMCU(MindMotion-MMCU),转载此文目的在于传递更多信息,版权归原作者所有。

围观 2672

一、WWDG 简介

窗口看门狗通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6 位变成 0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个MCU 复位。在递减计数器达到窗口寄存器数值之前,如果 7位的递减计数器数值(在控制寄存器中)被刷新,那么也将产生一个MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。

二、WWDG 主要特征

  •   可编程的自由运行递减计数器

  •   条件复位

      - 当递减计数器的值小于 0x40,(若看门狗被启动)则产生复位。
      - 当递减计数器在窗口外被重新装载,(若看门狗被启动)则产生复位。

  •   如果启动了看门狗并且允许中断,当递减计数器等于0x40 时产生早期唤醒中断(EWI),它可以被用于重装载计数器以避免WWDG 复位。

三、WWDG功能描述

如果看门狗被启动(WWDG_CR寄存器中的WDGA 位被置1),并且当 7位(T[6:0])递减计数器从0x40 翻转到0x3F(T6位清零)时,则产生一个复位。如果软件在计数器值大于窗口寄存器中的数值时重新装载计数器,将产生一个复位。

看门狗框图
MM32之窗口看门狗(WWDG)

应用程序在正常运行过程中必须定期地写入WWDG_CR 寄存器以防止MCU 发生复位。只有当计数器值小于窗口寄存器的值时,才能进行写操作。储存在WWDG_CR 寄存器中的数值必须在0xFF 和0xC0 之间:

1、启动看门狗

在系统复位后,看门狗总是处于关闭状态,设置WWDG_CR 寄存器的WDGA 位能够开启看门狗,随后它不能再被关闭,除非发生复位。

2、控制递减计数器

递减计数器处于自由运行状态,即使看门狗被禁止,递减计数器仍继续递减计数。当看门狗被启用时,T6 位必须被设置1,以防止立即产生一个复位。

T[5:0]位包含了看门狗产生复位之前的计时数目;复位前的延时时间在一个最小值和一个最大值之间变化,这是因为写入WWDG_CR寄存器时,预分频值是未知的。

配置寄存器(WWDG_CFR)中包含窗口的上限值:要避免产生复位,递减计数器必须在其值小于窗口寄存器的数值并且大于0x3F 时被重新装载,上图描述了窗口寄存器的工作过程。

另一个重装载计数器的方法是利用早期唤醒中断(EWI)。设置WWDG_CFR 寄存器中的WEI 位开启该中断。当递减计数器到达0x40 时,则产生此中断,相应的中断服务程序(ISR)可以用来加载计数器以防止WWDG 复位。

在WWDG_SR 寄存器中写0可以清除该中断。注:T6 位可以被用来产生一个软件复位(WDGA 位被置位,T6 位清零)

四、如何编写看门狗超时程序

下图显示了装载到看门狗计数器(CNT)中的 6 位计数值和看门狗的延迟时间之间的线性关系(以 mS为单位)。此图可用来做为快速计算的参考,而未将时间的偏差考虑在内。如果需要更高的精度,可以使用下图提供的计算公式。

当写入 WWDG_CR 寄存器时,始终置 T6 位为1以避免立即产生一个复位。

窗口看门狗时序图
MM32之窗口看门狗(WWDG)

五、设置WWDG实验分析

  •   实验内容简介
环境MM32L073PF Miniboard、MDK,设置WWDG,通过观察喂狗与不喂狗的复位现象。

  •   实验代码分析
首先看main函数
MM32之窗口看门狗(WWDG)
先初始化一个串口,方便我们观察复位现象,然后通过函数Wwdg_reset_ON 进行设置WWDG。最后在循环里通过WWDG_SetCounter函数不停的喂狗。
MM32之窗口看门狗(WWDG)
在函数Wwdg_reset_ON中设置窗口值,和计数器的初值。

  •   实验现象
1、当注释掉喂狗函数时,通过串口在不断打印可以看出,MCU一直在复位。
2、当不注释喂狗函数时,串口只打印一次,MCU没有复位。

来源:灵动微电子

围观 466

一、MM32嵌套向量中断控制器

本文针对MM32F0/L0/W0系列MCU产品。

特征

  ○ 中断都可屏蔽(除了 NMI)
  ○ 16 个可编程的优先等级(使用了 4 位中断优先级)
  ○ 低延迟的异常和中断处理
  ○ 电源管理控制
  ○ 系统控制寄存器的实现

嵌套向量中断控制器(NVIC)和处理器核的接口紧密相连,可以实现低延迟的中断处理和高效地处理晚到的中断。嵌套向量中断控制器管理着包括核异常等中断。关于更多的异常和 NVIC 编程的说明请参考 CPU 技术手册。

系统嘀嗒(SysTick)校准值寄存器

系统嘀嗒校准值固定为 9000,当系统嘀嗒时钟设定为 9MHz(HCLK/8 的最大值),产生1mS 时间基准。

中断和异常向量

下表列出了 MM32L0 系列产品的向量表。

MM32L0xx 系列产品的向量表

MM32F0/L0/W0系列MCU之EXTI

MM32F0/L0/W0系列MCU之EXTI

二、外部中断/事件控制器(EXTI)

外部中断和时间控制器(EXTI)管理外部和内部异步事件/中断,并生成相应的事件请求到 CPU/中断控制器和到电源管理的唤醒请求。

每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降
沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求。

功能说明

要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置 2 个触发寄存器,同时在中断屏蔽寄存器的相应位写1允许中断请求。当外部中断线上发生了期待的边沿时,将产生一个中断请求,对应的挂起位也随之被置1。在挂起寄存器的对应位写1,将清除该中断请求。

如果需要产生事件,必须先配置好并使能事件线。根据需要的边沿检测通过设置 2 个触发寄存器,同时在事件屏蔽寄存器的相应位写1允许事件请求。当事件线上发生了需要的边沿时,将产生一个事件请求脉冲,对应的挂起位不被置1。

通过在软件中断/事件寄存器写1,也可以通过软件产生中断/事件请求。

外部中断/事件线路映像

通用 I/O 端口以下图的方式连接到 16 个外部中断/事件线上:

外部中断通用 I/O 映像

MM32F0/L0/W0系列MCU之EXTI

另外其他的外部中断/事件控制器的连接如下:
  ○ EXTI 线 16 连接到 PVD 输出
  ○ EXTI 线 18 连接到 USB 唤事件
  ○ EXTI 线 19 连接到比较器 1 输出
  ○ EXTI 线 20 连接到比较器 2 输出

三、按键中断检测实验分析

实验内容简介

以MM32L073PF为例,将PA0连接到按键上,如果按键按下将会产生按键中断,在中断服务子程序中进行LED的翻转。

实验代码分析

首先我们从main函数开始分析,代码如下:

MM32F0/L0/W0系列MCU之EXTI

使用LED_Init()配置好LED所使用的I/O,并且关掉LED。然后进行外部中断的配置。
MM32F0/L0/W0系列MCU之EXTI

1. 选定要配置为 EXTI 的 I/O 口线和 I/O 口的工作模式。
2. 配置 EXTI 中断线 I/O。
3. EXTI 中断线工作模式配置。
4. 配置 EXTIx 线的中断优先级。

接下来看中断服务子函数:

MM32F0/L0/W0系列MCU之EXTI

在中断服务子函数里进行LED的翻转。

实验现象

下载好程序后,按下按键时LED点亮,再按下按键时LED熄灭,如此循环。

来源:灵动微电子

围观 401

页面

订阅 RSS - 灵动微电子