灵动微电子

在之前的微课堂中和大家分享过灵动MM32系列MCU的UART通信实例,在此实例的基础上我们增加UART 9bit通信功能。UART 9bit通信的作用是第9bit用于标识是地址或数据,第9bit 为1标识是从机地址,为0标识是数据,此外UART通信的第9bit也可作为数据的同步帧位使用。

在双机通讯中,UART的8bit通信的第九位一般是奇偶校验位,而多机通讯中,第九位用于标识地址或数据,常用1表示后面的是从机地址,0表示后面的是数据。我们通常希望只有被寻址的接收者才被激活,来接收随后的数据,这样就可以减少由未被寻址的接收器的参与带来的多余的UART服务开销。未被寻址的设备可启用其静默功能置于静默模式。在静默模式里,任何接收状态位都不会被设置,所有接收中断被禁止。

以MM32F013x系列MCU的UART通信为例,通过一个示例Demo介绍UART 9bit通信的同步帧方式。

一、与UART 9bit通信相关的寄存器

图1

如上图1所示为UART通用控制寄存器UART_CCR,在MM32F013x UM手册的第489和第490页有关于该寄存器位的详细描述。本实例用到的UART通用控制寄存器UART_CCR位说明如下:

Bit11

B8EN(rw, reset:0x00)UART同步帧发送第9bit使能控制位。该位使能后校验使能PEN不起作用。

1:使能同步帧第9bit发送。

库函数设置:

UART_Enable9bit(UART1, ENABLE)

0:禁止同步帧第9bit发送。

库函数设置:

UART_Enable9bit(UART1, DISABLE)

Bit10

B8TOG(rw,reset:0x00)UART同步帧发送第9bit自动翻转控制位。

1:使能第9bit自动翻转。

库函数设置:

UART_Set9bitAutomaticToggle(UART1, ENABLE)

0:禁止第9bit自动翻转。

库函数设置:

UART_Set9bitAutomaticToggle(UART1, DISABLE)

注:在 B8TXD 和 B8POL 的值相同时,在配置完寄存器后传输的第二个数据开始翻转,第一个数据默认为地址位。

Bit8

B8TXD(rw,reset:0x00)UART同步帧发送数据第9bit。

1:发送同步帧第9bit为高电平。

库函数设置:

UART_Set9bitLevel(UART1, ENABLE)

0:发送同步帧第9bit为低电平。

库函数设置:

UART_Set9bitLevel(UART1, DISABLE)

二、程序配置

初始化MM32F013x UART1 9bit通信

从官网下载MM32F013x例程,以MM32F0133C7P的UART1通信为例,增加与UART 9bit通信相关的寄存器位的初始化,这里以库函数方式给出,增加的3行代码如下所示:

//Synchronous frame enable bit UART_CCR Bit11:B8EN
UART_Enable9bit(UART1, ENABLE);
//Synchronous frame transmit UART_CCR Bit8: B8TXD
UART_Set9bitLevel(UART1, DISABLE);
//Synchronous frame auto toggle UART_CCR Bit10:B8TOG
UART_Set9bitAutomaticToggle(UART1, ENABLE);

MM32F0133C7P UART1 9bit通信,初始化代码如下所示:

void bsp_UART1_9Bit_Init(u32 baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
UART_InitTypeDef UART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);

GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
UART_StructInit(&UART_InitStructure);

UART_InitStructure.BaudRate = baudrate;
UART_InitStructure.WordLength = UART_WordLength_8b;
UART_InitStructure.StopBits = UART_StopBits_1;

UART_InitStructure.Parity = UART_Parity_No;
UART_InitStructure.HWFlowControl = UART_HWFlowControl_None;
UART_InitStructure.Mode = UART_Mode_Rx | UART_Mode_Tx;
UART_Init(UART1, &UART_InitStructure);

UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);
UART_Enable9bit(UART1, ENABLE);
UART_Set9bitLevel(UART1, DISABLE);
UART_Set9bitAutomaticToggle(UART1, ENABLE);

NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

UART_Cmd(UART1, ENABLE);
}

1 ● 编写MM32F013x UART1中断函数

MM32F013x UART1中断服务函数,同时将收到的数据发送出去,代码如下所示:

void UART1_IRQHandler(void)
{
u8 res;

if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)
{
//Receiving interrupts (data received must end at 0x0D 0x0a)
UART_ClearITPendingBit(UART1, UART_IT_RXIEN);

//read receive data.
res = UART_ReceiveData(UART1);

bsp_UART1_Send_Byte(res);
}
}

2 ● 编写MM32F013x UART1发送函数

使用之前工程的MM32F0133C7P UART1发送函数,代码如下所示:

void bsp_UART1_Send_Byte(u8 dat)
{
UART_SendData(UART1, dat);

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

MM32F013x UART1 9bit通信功能演示

在main函数中调用SysTick和UART1 9bit通信初始化函数,代码如下所示:

s32 main(void)
{
//SysTick init
DELAY_Init();
//UART1 9bit init
bsp_UART1_9Bit_Init(115200);

while(1)
{
bsp_UART1_Send_Byte(0x55);

DELAY_Ms(500);
}
}

编译工程代码,然后烧录软件到MM32F0133C7P核心板上,用逻辑分析仪抓取UART1 9bit通信发送数据和接收数据的波形:

演示发送数据:
以MM32F0133C7P发送0x55为例,使用逻辑分析仪抓取UART1 9bit通信发送数据的波形如下图所示。

图2

演示接收数据:
以上位机串口助手发送0xAA为例,使用逻辑分析仪抓取UART1 9bit通信收到的数据的波形,观察箭头所指第bit9位,如下图3所示:

图3

转自:灵动MM32MCU

围观 110

随着汽车电子技术的高速发展和广泛应用,实现智能化和网络化是汽车发展的必然趋势。为简化日益增加的汽车电控设备的线路连接,提升系统的可靠性和故障诊断水平,实现各电控设备之间的数据资源共享,并建成开发的标准化、模块化结构,汽车网络总线技术得到了很大发展。目前,已经开发出多种总线,如控制器局域网总线CAN、车内网络总线LIN、高速容错网络总线FlexRay、面向媒体的系统传输总线MOST、更高带宽和传输速率的车载以太网Ethernet等,这里给大家介绍在MM32F013x上实现LIN通信的功能应用。

Part.1 什么是LIN

LIN 是 Local Interconnect Network 的缩写,是基于 UART/SCI(Universal Asynchronous Receiver-Transmitter /Serial Communication Interface,通用异步收发器/串行通信接口)的低成本串行通信协议,可用于汽车、家电、办公设备等多种领域。本文主要针对在MM32F013x上实现LIN在分布式的汽车电子网络系统中的应用。

LIN总线特点

  • 低成本:几乎车规级微控制器都具备LIN 通信必需的硬件
  • 极少的信号线即可实现国际标准ISO9141 规定
  • 传输速率最高可达20Kbit/s
  • 单主控器/多从设备模式无需仲裁机制
  • 从节点不需晶振或陶瓷震荡器就能实现自同步,节省了从设备的硬件成本
  • 保证信号传输的延迟时间
  • 不需要改变LIN 从节点的硬件和软件就可以在网络上增加节点
  • 通常一个LIN 网络上节点数目小于12 个共有64 个标志符


Part.2 LIN总线 帧结构

帧(Frame)包含帧头(Header)和应答(Response)两部分。

帧头包括同步间隔段、同步段以及PID(Protected Identifier,受保护ID)段,应答包括数据段和校验和段。

如图所示,其中值“0”为显性电平(Dominant),值“1”为隐性电平(Recessive),总线上实行“线-与”:当总线上有大于等于一个节点发送显性电平时,总线呈显性电平;所有的节点都发送隐性电平或不发送信息(不发送任何信息时总线默认呈隐性电平)时,总线才呈现隐性电平,即显性电平起主导作用。


Part.3 程序配置

01、初始化MM32F013x UART1串口

从官网下载MM32F013x例程,参考MM32F0133C7P的UART例程的初始化以及中断服务函数,这里不在赘述。

02、LIN的发送

2.1 同步间隔段的发送

UART内部有Break信号的发送,通过使能LIN,即可实现LIN的间隔段,代码如下:

bool LINSendbreak(void)
{
uint16_t Tempcnt = 0;
UART2->CCR |= UART_CCR_LIN; //LIN Enable
UART2->CCR |= UART_CCR_BRK; //Send Break
while ((UART2->ISR & 0x00000080) == 0) //TXBRK_INTF
{
Tempcnt++;
if (Tempcnt > 5000)
return (false);
}
return (true);
}

2.2 数据的发送

数据的发送沿用原有的UART接口数据发送即可:

bool LINSendChar(uint8_t ch)
{
uint16_t Tempcnt = 0;

while ((UART2->CSR & UART_IT_TXIEN) == 0)//The loop is sent until it is finished
{
Tempcnt++;
if (Tempcnt > 5000)
return (false);
}
UART2->TDR = (ch & (uint16_t)0x00FF);
return (true);
}

2.3 数据包的发送

有了上面2个基础函数进行发送,现在来看下数据包的具体发送,从下图中可以看出数据包是根据保护段的定义来进行区分是发送信号帧还是诊断帧。


信号帧的数据就可以做成以下的方式:

bool LINSendMsg(void)
{
uint8_t check_sum, i;
frame_send.error = 0;
if (!LINSendbreak()) //Send Break
return (false);
if (!LINSendChar(0x55)) //Send Sync Byte
return (false);
msg_send.Data[0] = LINCalcParity(msg_send.Data[0]);
for (i = 0; i < 9; i++)
{
if (!LINSendChar(msg_send.Data[i])) //Send Data
return (false);
}
check_sum = LINCalcChecksum(msg_send.Data, 1);
if (!LINSendChar(check_sum)) //Send Checksum
return (false);
frame_send.state = IDLE;
return (true);
}

而诊断帧的就是:

bool LINSendID(void)
{
if (!LINSendbreak())
return (false);
if (!LINSendChar(0x55))
return (false);
msg_send.Data[0] = LINCalcParity(msg_send.Data[0]);
if (!LINSendChar(msg_send.Data[i]))
return (false);
return (true);
}

这样就可以在等待UART中断函数里收到从机返回的数据。

2.4 从机的接受与发送

从机收数据与正常的串口一样,只需要做BRK信号的处理即可,从机收到数据以后按正常的返回数据,返回数据就不需要发送BRK信号。

if (LIN_RxBuff[1] == LIN_PID_60_0x3C)
{
msg_send1.Data[0] = 0x3C;
msg_send1.Data[0] = LINCalcParity(msg_send1.Data[0]);
UART2->ICR |= UART_ICR_RXIDLE; //clear idle int bit
UART2->IER |= UART_IER_RXIDLE; //enable uart rx idle int
for (i = 1; i < 9; i++)
{
if (!LINSendChar(msg_send1.Data[i]))
return (false);
}
check_sum = LINCalcChecksum(msg_send1.Data, 1);
if (!LINSendChar(check_sum))
return (false);
}

Part.4 MM32F013x LIN通信功能演示

通过逻辑分析仪可以看到信号帧的数据:


而诊断帧数据就有从机回应的数据:


有这个演示作为基础就可以开发LIN的通讯产品了。

转自:灵动MM32MCU

围观 326

嵌入式工程师在开发产品中经常会用到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

围观 65

前面我们介绍了新出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

围观 180

灵动微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) 芯片系统时钟配置过程错误等等

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

围观 281

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

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

来源:灵动微电子

围观 33

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

围观 1044

近日,上海灵动微电子股份有限公司(以下简称“灵动微电子”)与上海华虹宏力半导体制造有限公司(以下简称“华虹宏力”)、通富微电子股份有限公司(以下简称“通富微电”)基于各自的技术实力和行业优势,优势互补,各展所长,共同助力智能硬件,特别是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

围观 27

号外!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

围观 49

页面

订阅 RSS - 灵动微电子