极海APM32F035低压通用电机控制板开箱和基本外设学习

分享作者:user201910137473
作者昵称:iCEasy商城-小易
评测品牌:极海半导体
评测型号:APM32F035
申请理由(产品应用):机器人制造
发布时间:2024-07-29 14:35:56
1
概要
首先感谢iCEasy商城举办的免费领取开发板活动,自己在商城上面申请的,很高兴自己可以通过审核获得的机会。收到开发板的时间挺快的,商城的小伙伴很给力。
开源口碑分享内容


打开包装可以看到开发板,为了防止在运输过程中电路板损坏,快递包裹的很结实,用了好几层的泡沫进行保护,可以看出商城小伙伴的用心。

APM32F035作为一款32位FoC矢量控制MCU,内置Vector Computer多种专用数学运算加速器,提供整套FoC控制算法支持。该款新品具有优异的高效运算与处理速度,丰富的模拟与连接特性赋予电机更多的新功能属性,有效提升电机驱动性能并降低用户产品运行成本,助力国内电机企业全面迈入“IE3高效时代”。

APM32F035具备满足各种电机控制应用的外设与内存,多种核心电机控制算法大幅提升电机效率,满足行业结构升级需求,广泛应用于风机、水泵、电动工具、园林工具、电动两/三轮车、冰箱压缩机等细分场景。

一:高效运算与处理速度,多种算法硬件配置

基于Arm® Cortex®-M0+内核,主频72MHz,支持MDU+Cordic与CRC,满足电机应用的处理性能;Flash 64KB,SRAM 10KB,满足电机嵌入式应用的各种算法需求;支持单周期32位硬件乘法器,内置M0CP协处理器以增强Cortex-M0+运行性能,其硬件配置包括移位单元、32bit /32bit除法器、乘加运算、开方、三角函数、SVPWM;集成电机专用PWM,支持互补、刹车,并可与M0CP联动。

二:集成资源丰富,支持多种模拟与连接功能

内置高精度模拟外设与数字外设,满足不同功能需求与高速连接应用需求。除常规外设如12位ADC(1Msps)、SPI、U(S)ART(支持全双工通信)、I2C、CAN外,新增                                                                                                            

三:领先的系统级生态服务能力,助力用户快速实现量产

极海具备完善的开发生态体系,提供灵活便捷、简单易用、丰富多样的软硬件开发工具,为广大工程师提供出色使用体验并快速实现量产。极海电机控制通用开发平台从应用层、中间层、器件层、硬件层、资深电机团队上提供全面的生态支持,包括客户支持、高低压通用电机平台、细分领域专用硬件、底层寄存器SDK、电机专用运算、多种算法选择、多种控制方式接入、以及全面的保护机制。

极海高/低压电机通用评估板适配各种高低压应用场景,用于初步方案验证,以及进行软件层面程序验证,帮助用户更好了解极海芯片特性,方便开发及进行算法移植测试。此外,极海提供完善的工具链、多场景DEMO,以及快速周到的技术支持服务,帮助用户实现快速量产。

等研究明白了这款开发板,再和大家分享心得。


我们将极海公司,利用keil的软件编译环境搭建简单的学习了一下,今天我们学习一下APM32F035的几个基本的外设。

  1. 新建APM32F305代码的工程

参考官方的sdk包里面代码:

值得注意的是:官方提供的启动文件里面的内容,尽量不要修改,否则导致程序运行出错。

一:    简单调试使用

基本上所有的开发板上面第一个功能介绍是如何创建工程,第二个就是简单介绍IO口的操作,而最直接的就是利用LED灯作为显示,这样能清晰的看到IO口的高低电平。

参考原理图:

整个电路板只有两个0603封装的LED灯,一个是用来指示电源电路是否正常,另外一个是故障指示灯(PC15),当IO口输出高电平时,指示灯熄灭,输出低电平时,指示灯亮起。

首先要初始化使用的IO口:

#define LEDn                             2

#define LED2_PIN                         GPIO_PIN_15

#define LED2_GPIO_PORT                   GPIOC

#define LED2_GPIO_CLK                    RCM_AHB_PERIPH_GPIOC

 void GPIO_Init(void)
{
  GPIO_Config_T gpioConfig;

  RCM_EnableAHBPeriphClock(LED2_GPIO_CLK | LED3_GPIO_CLK);
  /* LED2 GPIO configuration */
  gpioConfig.pin = LED2_PIN;
  gpioConfig.mode = GPIO_MODE_OUT;
  gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  gpioConfig.speed = GPIO_SPEED_50MHz;
  gpioConfig.pupd = GPIO_PUPD_NO;
  GPIO_Config(LED2_GPIO_PORT, &gpioConfig);

  /* LED3 GPIO configuration */
  gpioConfig.pin = LED3_PIN;
  GPIO_Config(LED3_GPIO_PORT, &gpioConfig);
}          

注意要使能PCIO口的时钟,要不然io口是不会工作的。

 void APM_MINI_DelayMs(__IO uint32_t nms)
{
  uint32_t temp;

  SysTick->LOAD = (uint32_t)nms * cntMs;
  SysTick->VAL = 0x00;
  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
  do
  {
      temp = SysTick->CTRL;
  }
  while ((temp & 0x01) && !(temp & (1 << 16)));
  SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
  SysTick->VAL = 0x00;
}

这里为了显示状态的改变时用了500ms的延时,当然本身这种延时函数是没有问题的,但是以后在工作中不要用类似的延时,很影响程序的运行。试验效果将在下面的视频中展示。

二:外部中断(EINT)简单调试使用

                                       
引脚输入信号引起的中断/事件,在中断向量表中指 EINTx;其它中断指内部中断
   
事件可分为硬件事件、软件事件。硬件事件是通过外部/内核硬件信号产生事件,
软件事件是通过指令产生事件。
中断需经过中断处理函数实现需要处理的工作;事件不需要经过中断处理函数,
可硬件触发预先设置的工作。外部事件例如可通过事件是 GPIO 输出脉冲,内部
事件例如通过一个 TMR 的更新事件触发另一个 TMR 工作。

这里我们用板载的按键K1(PC14)和LED灯(PC15)两个IO口调试这个功能。

中断初始化函数:

  void EINT_Init(void)
{
  GPIO_Config_T gpioConfig;
  EINT_Config_T eintConfig;

  /* Enable the BUTTON Clock */
  RCM_EnableAHBPeriphClock(KEY1_BUTTON_GPIO_CLK);
  RCM_EnableAHBPeriphClock(KEY2_BUTTON_GPIO_CLK);
//  RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
   
   
  RCM_EnableAPB2PeriphClock(RCM_AHB_PERIPH_GPIOC);    

  /* Condiv Button pin as input floating */
  gpioConfig.mode = GPIO_MODE_IN;
  gpioConfig.pupd = GPIO_PUPD_PU;
  gpioConfig.pin = KEY1_BUTTON_PIN;
  GPIO_Config(KEY1_BUTTON_GPIO_PORT, &gpioConfig);

  gpioConfig.pin = KEY2_BUTTON_PIN;
  GPIO_Config(KEY2_BUTTON_GPIO_PORT, &gpioConfig);

  /* Condiv GPIO pin used as EINT Line */
  SYSCFG_EINTLine(SYSCFG_PORT_GPIOC, SYSCFG_PIN_14);
  SYSCFG_EINTLine(SYSCFG_PORT_GPIOA, SYSCFG_PIN_0);

  /* Condiv Button exit line */
  eintConfig.line    =  KEY1_BUTTON_EXTI_LINE;
  eintConfig.lineCmd =  ENABLE;
  eintConfig.mode    =  EINT_MODE_INTERRUPT;
  eintConfig.trigger =  EINT_TRIGGER_FALLING;
  EINT_Config(&eintConfig);

  eintConfig.line    =  KEY2_BUTTON_EXTI_LINE;
  EINT_Config(&eintConfig);

  /* Condiv NVIC_IRQRequest */
  NVIC_EnableIRQRequest(EINT4_15_IRQn, 0x0F);
}              

这里需要将SDK包中的中断函数中的:EINT0_1_IRQn更改为EINT4_15_IRQn;IO口初始化时,将KEY1_BUTTON_GPIO_CLK的IO口定义更改为PC14,

但是我调试中断的时候发现,利用ST-LINK下载的时候,在仿真状态的时候,需要增加一个断点,程序才可以正常进入中断,但是我直接通电的时候,LED的指示灯是不正常工作的,我怀疑是中断函数根本就没有启作用。测试过上电延时200ms也没有解决。等有时间在弄这个bug吧。

   

原理图显示:

查询数据手册是串口2

主要代码如下:

int main(void)
{
   
       APM_MINI_DelayInit();
   
   
  GPIO_Config_T gpioConfig;
  USART_Config_T usartConfig;
  APM_MINI_COMInit(COM2);

  /* Enable GPIO clock */
  RCM_EnableAHBPeriphClock(MINI_COM1_TX_GPIO_CLK | MINI_COM2_TX_GPIO_CLK);

  /* Enable COM1 clock */
  RCM_EnableAPB2PeriphClock(MINI_COM2_CLK);

  /* Connect PXx to USARTx_Tx */
  GPIO_ConfigPinAF(MINI_COM2_TX_GPIO_PORT, MINI_COM2_TX_SOURCE, MINI_COM2_TX_AF);

  /* Connect PXx to USARRX_Rx */
  GPIO_ConfigPinAF(MINI_COM2_RX_GPIO_PORT, MINI_COM2_RX_SOURCE, MINI_COM2_RX_AF);

  /* Condiv USART Tx as alternate function push-pull */
  gpioConfig.mode = GPIO_MODE_AF;
  gpioConfig.pin = MINI_COM2_TX_PIN;
  gpioConfig.speed = GPIO_SPEED_50MHz;
  gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  gpioConfig.pupd = GPIO_PUPD_PU;
  GPIO_Config(MINI_COM2_TX_GPIO_PORT, &gpioConfig);

  /* Condiv USART Rx as input floating */
  gpioConfig.pin  = MINI_COM2_RX_PIN;
  GPIO_Config(MINI_COM2_RX_GPIO_PORT, &gpioConfig);

  /* MINI_USARTs condivd as follow:  */
  /* BaudRate = 115200 baud   */
  usartConfig.baudRate = 115200;
  /* Receive and transmit enabled  */
  usartConfig.mode = USART_MODE_TX_RX;
  /* Hardware flow control disabled (RTS and CTS signals) */
  usartConfig.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
  /* No parity  */
  usartConfig.parity = USART_PARITY_NONE;
  /* One Stop Bit  */
  usartConfig.stopBits = USART_STOP_BIT_1;
  /* Word Length = 8 Bits  */
  usartConfig.wordLength = USART_WORD_LEN_8B;
  /* USART_Config  */
  USART_Config(MINI_COM2, &usartConfig);

  /* Enable USART_Interrupt_RXBNEIE*/
  USART_EnableInterrupt(MINI_COM2, USART_INT_RXBNEIE);

  NVIC_EnableIRQRequest(MINI_COM2_IRQn, 2);

  /* Enable USART */
  USART_Enable(MINI_COM2);

  /* MINI_COM1 Send data to PC, and you need to open serial assistant to observe*/
   USART_Write(MINI_COM2, (uint8_t*)"芯查查 APM32F035通用控制板串口调试r\n");

  while (1)
  {
           
       APM_MINI_DelayMs(500);
USART_Write(MINI_COM2, (uint8_t*)"芯查查 APM32F035通用控制板串口调试r\n");
}

利用ISP-STC软件 查看一下串口数据:

    3的PWM输出功能调试

APM32的定时器资源是比较丰富的,由于板子上面只有将PA7引脚引出,查看手册PA7引脚是可以复用定时器3的复用1功能;资料如下图所示:

 void APM_MINI_TMR1_PWMOutPut_Init(void)
{
  TMR_TimeBase_T  timeBaseConfig;
  TMR_OCConfig_T  occonfig;
  GPIO_Config_T   gpioconfig;

  /* Enable Clock*/
  RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
//    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
//    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);

  /* Connect TMR1 to CH1 */
//    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN2);
//    gpioconfig.mode  = GPIO_MODE_AF;
//    gpioconfig.outtype = GPIO_OUT_TYPE_PP;
//    gpioconfig.pin   = GPIO_PIN_8;
//    gpioconfig.pupd  = GPIO_PUPD_NO;
//    gpioconfig.speed = GPIO_SPEED_50MHz;
//    GPIO_Config(GPIOA, &gpioconfig);
       RCM_EnableAPB1PeriphClock(RCM_APB2_PERIPH_SYSCFG);
  RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
   
  /* Connect TMR1 to CH1 */
  GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN1);
  gpioconfig.mode  = GPIO_MODE_AF;
  gpioconfig.outtype = GPIO_OUT_TYPE_PP;
  gpioconfig.pin   = GPIO_PIN_7;
  gpioconfig.pupd  = GPIO_PUPD_NO;
  gpioconfig.speed = GPIO_SPEED_50MHz;
  GPIO_Config(GPIOA, &gpioconfig);    
   
   
   
  /* Set clockDivision = 1 */
  timeBaseConfig.clockDivision = TMR_CKD_DIV1;
  /* Up-counter */
  timeBaseConfig.counterMode = TMR_COUNTER_MODE_UP;
  /* Set divider = 47 .So TMR1 clock freq ~= 48/(47+1) = 1MHZ */
  timeBaseConfig.div = 47 ;
  /* Set counter = 1000 */
  timeBaseConfig.period = 500-1;
  /* Repetition counter = 0x0 */
  timeBaseConfig.repetitionCounter = 0;
  TMR_ConfigTimeBase(TMR3, &timeBaseConfig);

  /* PWM1 mode */
  occonfig.OC_Mode = TMR_OC_MODE_PWM2;
  /* Idle State is reset */
  occonfig.OC_Idlestate = TMR_OCIDLESTATE_RESET;
  /* NIdle State is reset */
  occonfig.OC_NIdlestate = TMR_OCNIDLESTATE_RESET;
  /* Enable CH1N ouput */
  occonfig.OC_OutputNState = TMR_OUTPUT_NSTATE_DISABLE;
  /* Enable CH1 ouput */
  occonfig.OC_OutputState = TMR_OUTPUT_STATE_ENABLE;
  /* CH1  polarity is high */
  occonfig.OC_Polarity = TMR_OC_POLARITY_HIGH;
  /* CH1N polarity is high */
  occonfig.OC_NPolarity = TMR_OC_NPOLARITY_HIGH;
  /* Set compare value */
  occonfig.Pulse = 250-1;
  TMR_OC2Config(TMR3, &occonfig);

  /* Enable PWM output */
  TMR_EnablePWMOutputs(TMR3);
  /* Enable TMR1  */
  TMR_Enable(TMR3);
}

 上述代码是在定时器1的代码进行修改的。需要修改引脚配置,定时器3的时钟和PWM的输出函数,当所有配置完成后,最后再使能定时器3,实际效果如下图:

输出脉冲计算公式:48MHZ/48 =1M;

1M/500 = 2000  = 2K;占空比修改              该项参数;

(偷偷问一句:用商城兑换的手持示波器会不会有BUFF加成)

具体定时时间很好计算,主频是120mhz,然后arr好prc是199和999,所以每次触发的时间就是1ms,之后是定时器的回调函数

ADC调试过程:

APM32内部ADC介绍:   位精度的   ,共   个通道,   个外部通道和  个内部通道,各通道   转换模式有单次、连续和断续,    转换结果可以左对齐或右对齐存储在   位数据寄存器中。

查看原理图,板载了一个10K的电位器,需要将PA7的引脚进行修改;代码如下:

 void ADC_Init(void)
{
  ADC_Config_T  adcConfig;
  GPIO_Config_T gpioConfig;
  /* RCM Enable*/
       /* RCM Enable*/
  RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
  RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC);
  RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
  /* GPIO Configuration */
  gpioConfig.pin = GPIO_PIN_7;
  gpioConfig.mode = GPIO_MODE_AN;
  gpioConfig.pupd = GPIO_PUPD_PU;
  GPIO_Config(GPIOA, &gpioConfig);
  /* ADC Configuration */
  ADC_Reset();
  ADC_ConfigStructInit(&adcConfig);
  /* Set resolution*/
  adcConfig.resolution    = ADC_RESOLUTION_12B;
  /* Set dataAlign*/
  adcConfig.dataAlign     = ADC_DATA_ALIGN_RIGHT;
  /* Set scanDir*/
  adcConfig.scanDir       = ADC_SCAN_DIR_UPWARD;
  /* Set convMode continous*/
  adcConfig.convMode      = ADC_CONVERSION_CONTINUOUS;
  /* Set extTrigConv*/
  adcConfig.extTrigConv1  = ADC_EXT_TRIG_CONV_TRG7;
  /* Set TrigEdge*/
  adcConfig.extTrigEdge1  = ADC_EXT_TRIG_EDGE_NONE;

  ADC_Config(&adcConfig);
  ADC_ConfigChannel(ADC_CHANNEL_7, ADC_SAMPLE_TIME_239_5);
  /* Enable Interrupt*/
  ADC_EnableInterrupt(ADC_INT_CS);

  NVIC_EnableIRQRequest(ADC_COMP_IRQn, 2);

  /* Enable VREFINT*/
  ADC_EnableVrefint();

  /* Calibration*/
  ADC_ReadCalibrationFactor();
  /* Enable ADC*/
  ADC_Enable();
}
void ADC_Isr(void)
{
  uint32_t adcData = 0;
  float voltage = 0.0;

  if (ADC_ReadIntFlag(ADC_INT_FLAG_CS) == SET)
  {
      ADC_ClearIntFlag(ADC_INT_FLAG_CS);
      /* Read ADC Conversion value */
      adcData = ADC_ReadConversionValue();

      voltage = ((float)adcData / 4095) * 3300;

      /* output to serial port */
      printf("Vref voltage : %.3f mV\r\n", voltage);

      APM_MINI_LEDToggle(LED2);
      APM_MINI_DelayMs(500);
  }
}

初始化ADC,并配置PA7为输入模式,更改中断号就可以正常调试;但是内部的ADC调试的时候会存在误差的,我在调试的时候发现,内部AD到不了满值,

全部评论
暂无评论
0/144