打印

[M0+] STM32G070RB Nucleo开发板评测

[复制链接]
1066|8
跳转到指定楼层
楼主
本帖最后由 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开发板都差不多, 我最关注的还是芯片本身.
图 Nucleo-G070RB正面

图 Nucleo-G070RB反面


after_selected_default_config.png (320.7 KB, 下载次数: 3)

after_selected_default_config.png

code_generate_toolchain_type.png (42.57 KB, 下载次数: 4)

code_generate_toolchain_type.png

cubemx_select_f070_nucleo_board.png (420.66 KB, 下载次数: 4)

cubemx_select_f070_nucleo_board.png

cubemx_splash.png (15.46 KB, 下载次数: 5)

cubemx_splash.png

default_board_config_confirm.png (14.65 KB, 下载次数: 3)

default_board_config_confirm.png

en.STM32G0x0_Value_line_LN2050.jpg (34.75 KB, 下载次数: 3)

en.STM32G0x0_Value_line_LN2050.jpg

en.STM32G0x1_line_LN2048.jpg (192.34 KB, 下载次数: 4)

en.STM32G0x1_line_LN2048.jpg

stdout_retarget.png (472.89 KB, 下载次数: 3)

stdout_retarget.png

stm32g0_series_feature_matrix.png (265.88 KB, 下载次数: 3)

stm32g0_series_feature_matrix.png

usart_7bit_badcode.png (77.25 KB, 下载次数: 2)

usart_7bit_badcode.png

usart_7bit_to_8bit.png (57.21 KB, 下载次数: 2)

usart_7bit_to_8bit.png

使用特权

评论回复
沙发
 楼主 | 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兼容的, 所以开发者根据产品的具体功能需求在硬件设计上可以灵活替换.  


使用特权

评论回复
板凳
 楼主 | 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就可生成工程框架.


使用特权

评论回复
地板
 楼主 | 2019-4-11 22:11 | 只看该作者


图 选择代码工程输出类型

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


图 重定向串口到printf


在主文件中添加这个函数:
  1. int stdout_putchar (int ch)
  2. {
  3.         uint8_t c = ch;
  4.         HAL_UART_Transmit(&huart2, &c, 1, 1);
  5.         return ch;
  6. }
复制代码

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

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


使用特权

评论回复
5
 楼主 | 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, 注意用的是数组声明是绝对定位:
  1. #define ARRAY_ADDRESS_START    (0x20002000UL)
  2. #define ARRAY_SIZE             MPU_REGION_SIZE_256B
  3. #define ARRAY_REGION_NUMBER    MPU_REGION_NUMBER3


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

  5. void MPU_Config(void) {
  6.   MPU_Region_InitTypeDef MPU_InitStruct = {0};

  7.   HAL_MPU_Disable();

  8.   /* Configure RAM region as Region N°0, 256KB of size and R/W region */
  9.   MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  10.   MPU_InitStruct.BaseAddress = EXAMPLE_RAM_ADDRESS_START;
  11.   MPU_InitStruct.Size = EXAMPLE_RAM_SIZE;
  12.   MPU_InitStruct.AccessPermission = portMPU_REGION_READ_WRITE;
  13.   MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  14.   MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  15.   MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  16.   MPU_InitStruct.Number = EXAMPLE_RAM_REGION_NUMBER;
  17.   MPU_InitStruct.SubRegionDisable = 0x00;
  18.   MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  19.   HAL_MPU_ConfigRegion(&MPU_InitStruct);

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

  24.   HAL_MPU_ConfigRegion(&MPU_InitStruct);

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

  31.   HAL_MPU_ConfigRegion(&MPU_InitStruct);

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

  35. void MPU_AccessPermConfig(void) {
  36.   MPU_Region_InitTypeDef MPU_InitStruct = {0};

  37.   HAL_MPU_Disable();

  38.   MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  39.   MPU_InitStruct.BaseAddress = ARRAY_ADDRESS_START;
  40.   MPU_InitStruct.Size = ARRAY_SIZE;
  41.   MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;
  42.   MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  43.   MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  44.   MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  45.   MPU_InitStruct.Number = ARRAY_REGION_NUMBER;
  46.   MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  47.   MPU_InitStruct.SubRegionDisable = 0x00;
  48.   MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  49.   HAL_MPU_ConfigRegion(&MPU_InitStruct);

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

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

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

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

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

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

6.参考与下载

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




使用特权

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

使用特权

评论回复
7
| 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
从图片那里显示的附件删掉就行了 
扫描二维码,随时随地手机跟帖
*滑动验证:
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

关闭

热门推荐上一条 /4 下一条

在线客服 快速回复 返回顶部 返回列表
全民彩票