[M0+]

STM32G070RB Nucleo开发板评测

[复制链接]
5001|14
手机看帖
扫描二维码
随时随地手机跟帖
zhanzr21|  楼主 | 2019-4-11 22:01 | 显示全部楼层 |阅读模式
本帖最后由 zhanzr21 于 2019-4-11 22:02 编辑

1.前言

最近ST公司新品不断, 一段时间没有关注这个再上官网一看: 内容更新好多. 其中之一就是发布了G0系列的产品. ST还联合媒体举行了"旧板换新板"的活动. 开发板我是有很多的, 说实在的很多开发板就是刚开始拿到手体验个新鲜, 之后都被"打入冷宫". 日常工作还是很繁忙的, 如果纯粹的"玩板子", 工程师确实没有很多时间投入. 但是ST的开发板不同, 很少有被束之高阁的. 原因很简单, 因为日常开发测试经常要用到. 尤其是Nucleo系列的开发板, 我经常使用. 在产品的开发初期, 用开发板来验证设计,想法是很方便的.能节省不少工夫. 所以看到"以旧换新"的活动, 我就毫不犹豫的参加了. 把另外一家的Cortex M0的开发板换了G0的开发板. ST家的Cortex M0的开发板我也有不少,但舍不得拿出来换, 因为还是要经常用的. STM32G070RB Nucleo的开发板如愿换到手了, 试用了下还是很喜欢的. 这里把自己的一些体会写下, 希望能给读者带一点信息.

2. 板子芯片内核-Nucleo/ST/Cortex
就Nucleo开发板本身而言, 起码对我来讲没有什么新鲜感, 甚至有点"审美疲劳". 因为所有Nucleo开发板都差不多, 我最关注的还是芯片本身.
g0_nulceo_front.jpg
图 Nucleo-G070RB正面
g0_nucleo_back.jpg

图 Nucleo-G070RB反面


after_selected_default_config.png
code_generate_toolchain_type.png
cubemx_select_f070_nucleo_board.png
cubemx_splash.png
default_board_config_confirm.png
en.STM32G0x0_Value_line_LN2050.jpg
en.STM32G0x1_line_LN2048.jpg
stdout_retarget.png
stm32g0_series_feature_matrix.png
usart_7bit_badcode.png
usart_7bit_to_8bit.png

使用特权

评论回复

相关帖子

zhanzr21|  楼主 | 2019-4-11 22:04 | 显示全部楼层
不过还是啰嗦几句, 因为也不是每个人都对这板子很熟. 要是大学生,或者刚入行的工程师, Nucleo G070RB开发板是他们第一个ST开发板也有可能的. Nucleo开发板是ST公司官方推出的一系列简配版开发板. 根据目标芯片的封装, 有Nucleo32, Nucleo64, Nucleo144几种. 为什麽说是"简配版", 因为Nucleo系列的开发板都是非常简单. 基本上就是"Debugger + 目标芯片 + 连接器". 有些Nucleo板子上还有目标芯片的USB接口/以太网接口等等. 简单有简单的好处, 就是把几乎所有芯片引脚与资源都开放出来了. 作为工程师, 你如果把Nucleo开发板利用起来, 对效率提升非常大. 除了"简配版"的Nucleo系列之外, ST官方还有"Discovery"与"Eval"系列的开发板, 那些开发板都有不少外设, 更适合"玩". 我也有不少"Discovery", "Eval"开发板, 实话说基本上没什么时间"玩". 当然我个人是希望多一点时间来"玩"这些开发板. 以后有时间再来细说. 这里我们把话题收一收, 现在主要讨论Nucleo F070RB开发板.
这次推出G0系列, 事实上有三个系列:
STM32G070:                        低成本系列
STM32G071:                        主流功能系列                       
STM32G081:                        安全系列

图 G0系列功能图



图 G070系列产品



图 G071, G081系列还有即将上市的其他系列



上图中也看的出, G070是目前推出最低端的系列(马上会有更低端的系列推出), G0x1的很多高级功能:DAC, USBPD, USB, CAN, 安全存储, AES硬件加速在G070上没有的.
尽管如此, G070系列还是有如下亮点:
1. 90nm工艺, F0系列是180nm工艺. 之前的L4系列也是用的90nm工艺. 这个对功耗影响很大, 可以说G0系列至少可以达到L4系列级别, 但是功能上G0系列对标的是F0系列. 可以说G0是F0的低功耗升级版本.
2. Cortex M0+内核, 这个对于F0的Cortex M0而言是升级. 其实STM之前的L0系列也是Cortex M0+. 只能说G0系列主要是用来替代F0系列的, 所以也算升级.
3. G0x0与G0x1是Pin2Pin兼容的, 所以开发者根据产品的具体功能需求在硬件设计上可以灵活替换.  


使用特权

评论回复
zhanzr21|  楼主 | 2019-4-11 22:09 | 显示全部楼层
3.Demo1: 使用CubeMX生成工程

下面来体验一下使用CubeMX生成第一个工程: Hello World + Blink.
CubeMX最近又有了很大的改版, 从4.x升级到5.x. 从个人角度来讲, 这个工具还有很大的提升空间. 不过横向比较的话, 目前ST在这方面做的是最好的了. 我经常使用它, 快速图形化生成工程, 配置功能. 可以说因为CubeMX的存在, STM32系列芯片增色不少. 因为时间, 人力是非常宝贵的.
安装CubeMX就不多说了, 很简单的操作. 直接打开CubeMX, 这里有一个吐槽点, 就是每次打开强制下载最新的硬件描述信息, 个人认为应该按需下载:

图 CubeMX打开后的强制下载最新信息窗口


网速好的话一会就下载完了, 要是知道板子型号的话使用左边的过滤器很快就可找到Nucleo F070RB板子模板. 使用芯片作为模板也可以, 只是用板子模版有一些现成的配置可利用. 本人的原则一向就是:节省时间,快速干活.


图 选择开发板模板

接下来问你是否使用默认配置, 个人认为这也是多余的一问, 如果使用自定义配置, 直接选芯片还选板子干什么.


图 默认配置确认窗口

之后终于到了项目编辑阶段. 因为已经使用了默认配置, 所以只需要小小修改即可.


图 项目编辑窗口

注意这里有个小坑, 默认配置USART使用7bit通信模式. 如果不注意同步修改调试工具的配置那么运行后输出就是乱码. 当然也可以修改调试工具的配置, 但是还是按照常规思维将串口改为8bit模式为好.


  • 图 按照7bit配置初初的乱码

按照常规思维这里改成8bit模式:


图 常规思维的8bit配置


7bit, 9bit这些模式在实际工程中的确有用到的场合, 如仅仅传输0-127的数据时用7bit可以提升速率, 主从组网时使用9bit多一个控制位. 还有些芯片与工具可以支持最低5bit模式, 理由就是32个位置可以传输A-Z的字母集了. 但是默认配置7bit模式感觉是故意给工程师出附加题的节奏.
其余外设视乎需要而配置, 本人还配置了ADC, GPIO等外设. 这里不一一详述. 后面会给出参考设计的下载地址. 一切配置结束后选择代码生成输出类型, 本人使用Keil MDK, 读者按需选择. 最后点击Generate Code就可生成工程框架.


使用特权

评论回复
zhanzr21|  楼主 | 2019-4-11 22:11 | 显示全部楼层


图 选择代码工程输出类型

如果第一次打开G0系列的工程, Keil MDK还会让你下载一个DFP. 按照提示操作即可, 总之工程自动化程度的提高也是有代价的, 代价就是安装很多支持包. 总体而言是值得的. 生成的工程直接就可以编译下载运行了, 但是要看出点效果来还得加几句, 本人添加的是打印ADC的采样值, 还有LD4闪烁.另外还要重定向USART2到pritnf.


图 重定向串口到printf


在主文件中添加这个函数:
int stdout_putchar (int ch)
{
        uint8_t c = ch;
        HAL_UART_Transmit(&huart2, &c, 1, 1);
        return ch;
}

其余代码不赘述, 感兴趣的直接下后文代码. 注意如果你的用户代码要避免下次自动生成代码被覆盖的话, 要加在这种宏之间:
  /* USER CODE BEGIN 2 */
        HAL_ADC_Start_DMA(&hadc1, (uint32_t*)g_adc_buf, sizeof(g_adc_buf)/sizeof(g_adc_buf[0]));
        printf("Clock:%u Hz\n", SystemCoreClock);
  /* USER CODE END 2 */

到这里就编译下载运行看结果了. 所有代码都在后文有下载连接.


使用特权

评论回复
zhanzr21|  楼主 | 2019-4-11 22:14 | 显示全部楼层
4.Demo2: MPU使用,Privileged与Unprivileged

G0系列主要是用来替代F0系列的产品, 所以从Cortex M0到Cortex M0+算是一个升级. Cortex M0与Cortex M0+的区别很细微, 很多不注意细节的工程师可能还说不出来两者到底有什么差别. 其实ARM公司当初推出Cortex M0的初衷就是替换8bit, 16bit的产品, 但是很多市场的变化就是嵌入式软件复杂度一直在增加. 所以Cortex M0被删除的一些功能在Cortex M0+上又补回来了. 当然其中很多Cortex M0+新增的功能都是Optional, 即可实现也可不实现. 对设计软件的工程师而言Cortex M0+相对于Cortex M0的改变有如下几点比较重要:
  • 1. 流水线从三级变成了两级, 这是为功耗与中断响应速度而考虑的改进
  • 2. VTOR可选, Cortex M0的中断向量是不能有偏移量的, 这点设计过Bootloader的程序员会感受很深.
  • 3. MPU可选, 做过RTOS的任务间隔离的程序员会感受很深.
  • 4. 两级CPU权限:privileged和unprivileged两种权限状态. Cortex M0也有这两种权限, 只是两种权限完全一样, 所以等于没有.

这里做个Demo展示一下MPU与两级内核状态的使用. 设计目的: 有一个数组, 在用户态仅仅允许读, 在内核态可读可写. 这种设计在Cortex M0上基本上不可能. 在Cortex M0+的芯片如STM32G0F70上, 利用MPU和CPU权限可以轻易做到.
首先声明数组,配置MPU, 注意用的是数组声明是绝对定位:
#define ARRAY_ADDRESS_START    (0x20002000UL)
#define ARRAY_SIZE             MPU_REGION_SIZE_256B
#define ARRAY_REGION_NUMBER    MPU_REGION_NUMBER3


uint8_t PrivilegedReadOnlyArray[32] __attribute__((at(ARRAY_ADDRESS_START)));

void MPU_Config(void) {
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  HAL_MPU_Disable();

  /* Configure RAM region as Region N°0, 256KB of size and R/W region */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = EXAMPLE_RAM_ADDRESS_START;
  MPU_InitStruct.Size = EXAMPLE_RAM_SIZE;
  MPU_InitStruct.AccessPermission = portMPU_REGION_READ_WRITE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.Number = EXAMPLE_RAM_REGION_NUMBER;
  MPU_InitStruct.SubRegionDisable = 0x00;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Configure FLASH region as REGION N°1, 1MB of size and R/W region */
  MPU_InitStruct.BaseAddress = EXAMPLE_FLASH_ADDRESS_START;
  MPU_InitStruct.Size = EXAMPLE_FLASH_SIZE;
  MPU_InitStruct.Number = EXAMPLE_FLASH_REGION_NUMBER;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Configure Peripheral region as REGION N°2, 512MB of size, R/W and Execute
  Never region */
  MPU_InitStruct.BaseAddress = EXAMPLE_PERIPH_ADDRESS_START;
  MPU_InitStruct.Size = EXAMPLE_PERIPH_SIZE;
  MPU_InitStruct.Number = EXAMPLE_PERIPH_REGION_NUMBER;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enable MPU (any access not covered by any enabled region will cause a fault) */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

void MPU_AccessPermConfig(void) {
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  HAL_MPU_Disable();

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = ARRAY_ADDRESS_START;
  MPU_InitStruct.Size = ARRAY_SIZE;
  MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.Number = ARRAY_REGION_NUMBER;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.SubRegionDisable = 0x00;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enable MPU (any access not covered by any enabled region will cause a fault) */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
主函数中调用上述函数以使能MPU, 并且切换至用户状态:
 MPU_Config();
  MPU_AccessPermConfig();       
  __set_CONTROL(THREAD_MODE_UNPRIVILEGED | SP_MAIN);  
  __ISB();
接下来实验读写权限:

printf("%s %u\n", __func__, __LINE__);
                printf("%s %u %02X\n", __func__, __LINE__, PrivilegedReadOnlyArray[0]);
这句没毛病, 只是读.
这句就会引起HardFault, 因为在用户状态这个数组是不允许写的.

PrivilegedReadOnlyArray[0] = (uint8_t)HAL_GetTick();
                printf("%s %u %02X\n", __func__, __LINE__, PrivilegedReadOnlyArray[0]);
那么要写怎么办?
答案就是使用SVC指令进入内核权限.

asm_svc_2(HAL_GetTick());                
                printf("%s %u %02X\n", __func__, __LINE__, PrivilegedReadOnlyArray[0]);
注意asm_svc_2这个是汇编语言写的函数, 要放在另外的.s文件中,详情直接看后文的代码下载连接.

;Supervisor Call 2
        ALIGN
asm_svc_2 FUNCTION   
        EXPORT asm_svc_2
        SVC #2
        bx lr       
        ENDP
注意要将SVC_Handler的声明改成有参数输入, 生成的代码是没有参数输入的. 按照AAPS的调用规约, 这个函数可以有输入参数. 为了求简便, 没有区分SVC号, 实际工程中这样就比较浪费SVC号了.

void SVC_Handler(uint32_t input){
        PrivilegedReadOnlyArray[0] = (uint8_t)input;
}
这样就可以达到设计目的了.

6.参考与下载

ST官方G0系列产品页面 https://www.st.com/en/microcontrollers-microprocessors/stm32g0-series.html
本文所有代码, 注意每个实验一个branch: https://github.com/zhanzr/stm32g0-demo.git




使用特权

评论回复
zhanzr21|  楼主 | 2019-4-11 22:16 | 显示全部楼层
@巧克力娃娃 好久没有发贴了, 如果想用相册图片, 一次性上传后, 主贴上没用到的图片都会自动当附件显示. 这个怎么破?

使用特权

评论回复
巧克力娃娃| | 2019-4-12 11:09 | 显示全部楼层
zhanzr21 发表于 2019-4-11 22:16
@巧克力娃娃 好久没有发贴了, 如果想用相册图片, 一次性上传后, 主贴上没用到的图片都会自动当附件显示. 这 ...

我不太懂!   @21ic小喇叭  你知道吗?

使用特权

评论回复
评论
zhanzr21 2019-4-12 13:22 回复TA
@21ic小喇叭 :没有操作成功,你帮忙操作下,这些是上传到某相册,后面回帖会用到,不能完全删除。就是不想显示在首贴下(除了主动编辑插到原文中的之外). 
21ic小喇叭 2019-4-12 13:11 回复TA
从图片那里显示的附件删掉就行了 
mnh12232| | 2019-6-30 10:46 | 显示全部楼层
牛掰,回帖支持楼主!

使用特权

评论回复
评论
zhanzr21 2019-6-30 22:00 回复TA
谢谢支持, 对这方面的研究一直没有停, 只是贴子没有更新了. 一定会找时间把新的内容整理发出来的. 
HXM1593| | 2019-7-13 17:30 | 显示全部楼层
本帖最后由 HXM1593 于 2019-7-13 17:31 编辑

我按照这个教程搞的STM32CUBEMX,使用的070这个板,没有成功。增加的就楼主这几行。
编译、生成都行。
MDK 5.25
STM32CUBEMX 5.01
楼主能提供DEMO1 这个工程吗?想对比一下,看看那的问题。
下载调试时候弹出来,出现这个问题,解决不了
QQ截图20190713093510.png QQ截图20190713094343.png
  
GitHub 看不懂呀

使用特权

评论回复
zhanzr21|  楼主 | 2019-7-14 00:31 | 显示全部楼层
HXM1593 发表于 2019-7-13 17:30
我按照这个教程搞的STM32CUBEMX,使用的070这个板,没有成功。增加的就楼主这几行。
编译、生成都行。
MDK  ...

不是代码的问题, 配置的问题. 你可以先试试最简单的工程不要加代码.

使用特权

评论回复
zhanzr21|  楼主 | 2019-7-14 00:33 | 显示全部楼层
git 很好用的, 如果这辈子想吃码农这碗饭 , 就用这机会学学git吧. 真的好用.
$ git clone https://github.com/zhanzr/stm32g0-demo.git

使用特权

评论回复
重岀江湖3| | 2019-7-30 15:31 | 显示全部楼层
点赞

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都進步

91

主题

1005

帖子

34

粉丝