CMS32L051调试小记(一)之代码选项配置

一、前言

最近使用一款国产32位MCU做产品开发,与之前用过的传统32位MCU相比,代码配置上遇到了一些自己未曾接触过的写法,这里做个随笔,方便日后回顾。

二、CMS32L051芯片介绍

1、芯片概述

在这里插入图片描述
这里直接摘抄手册中的功能描述,可自行与其它同类芯片比较。这里给出获取芯片相关资料的网址,包含基本的数据手册、应用手册、PACK包和例程。
芯片资料链接:点击此处

三、芯片在KEIL中的初始化配置

这里默认你已经获取了上面提到的所有相关资料。

1、启动文件

在这里插入图片描述
打开启动文件,找到汇编代码中关于Reset_Handler这一部分。与其它通用32位MCU一样,先会运行SystemInit()这个函数,再跑到main()函数中。

2、SystemInit()函数

void SystemInit (void)
{
/* ToDo: add code to initialize the system
         do not use global variables because this function is called before
         reaching pre-main. RW section maybe overwritten afterwards. */

  /* RAM Parity Error Reset Disable */
  SAF->RPECTL = 0x80U;

  CGC->WDTCFG0 = 0x1A;
  CGC->WDTCFG1 = 0x2B;
  CGC->WDTCFG2 = 0x3C;
  CGC->WDTCFG3 = 0x4D;
  DBG->DBGSTOPCR = 0;

  SystemCoreClock = CLK_GetHocoFreq();

  /* NVIC Clear Pending IRQ */
  NVIC->ICPR[0U] = 0xFFFFFFFF;

  /* NVIC Enable IRQs */
  NVIC->ISER[0U] = 0xFFFFFFFF;

  /* NVIC Lower Priority */
  NVIC->IP[0U] = 0xC0C0C0C0;
  NVIC->IP[1U] = 0xC0C0C0C0;
  NVIC->IP[2U] = 0xC0C0C0C0;
  NVIC->IP[3U] = 0xC0C0C0C0;
  NVIC->IP[4U] = 0xC0C0C0C0;
  NVIC->IP[5U] = 0xC0C0C0C0;
  NVIC->IP[6U] = 0xC0C0C0C0;
  NVIC->IP[7U] = 0xC0C0C0C0;

  /* restart watchdog timer */
  WDT->WDTE = 0xACU;   
}
  • 文件在system_CMS32L051.c中。大概操作了RAM的奇偶校验、看门狗配置、NVIC配置以及获取系统时钟。等等,没看到系统时钟配置啊,怎么就获取时钟频率了?进去看看。

3、CLK_GetHocoFreq()函数

/*----------------------------------------------------------------------------
  Clock functions
 *----------------------------------------------------------------------------*/
uint32_t CLK_GetHocoFreq(void)
{

  uint32_t freq;
  uint8_t  frqsel  = (*(uint8_t *)0x000000C2U);
           frqsel &= 0xF8;  	/* Mask the lower 3 bits */
           frqsel |= CGC->HOCODIV;	/* Refer the value of HOCODIV */ 
		   
  freq = 1000000U;  /* fIH = 1MHz except for the following cases */
		
  switch(frqsel)
  {
      case HOCO_FREQ_64MHZ: 
          freq = 64000000U; 	/* fIH = 64MHz 	*/
          break;
      case HOCO_FREQ_48MHZ: 
          freq = 48000000U; 	/* fIH = 48MHz 	*/
          break;
      case HOCO_FREQ_32MHZ: 
          freq = 32000000U; 	/* fIH = 32MHz 	*/
          break;
      case HOCO_FREQ_24MHZ: 
          freq = 24000000U; 	/* fIH = 24MHz 	*/
          break;
      case HOCO_FREQ_16MHZ: 
          freq = 16000000U; 	/* fIH = 16MHz 	*/
          break;
      case HOCO_FREQ_12MHZ: 
          freq = 12000000U; 	/* fIH = 12MHz 	*/
          break;
      case HOCO_FREQ_8MHZ: 
          freq = 8000000U; 	/* fIH = 8MHz 	*/
          break;
      case HOCO_FREQ_6MHZ: 
          freq = 6000000U; 	/* fIH = 6MHz 	*/
          break;
      case HOCO_FREQ_4MHZ: 
          freq = 4000000U; 	/* fIH = 4MHz 	*/
          break;
      case HOCO_FREQ_3MHZ: 
          freq = 3000000U; 	/* fIH = 3MHz 	*/
          break;
      case HOCO_FREQ_2MHZ: 
          freq = 2000000U; 	/* fIH = 2MHz 	*/
          break;
  }

  return(freq);
}
  • 大致看了下,先获取了0x000000C2U这个地址上的内容,再清除其中的低3位,与HOCODIV这个寄存器上的内容相或。读到的内容再处理下,返回对应的频率值。
    在这里插入图片描述 - 翻看手册,这里是读的字节选项上的内容,看来低3位似乎就是切换频率的位了,可看了启动文件,这就是最前面的运行代码了,代码中又是如何配置的呢?

4、代码选项配置

/*----------------------------------------------------------------------------
  User Option Byte 
 *----------------------------------------------------------------------------*/
/* ToDo: add here your necessary defines for device initialization
         following is an example for different system frequencies */

//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
const uint8_t user_opt_data[4] __attribute__((used)) __attribute__((section(".ARM.__AT_0x000000C0"))) =
{

/**
 * @brief WDT Control BYTE
 * Please refer to the user manual for details.
 *     7   |    6    |    5    |   4   |   3   |   2   |   1   |   0
 * --------|---------|---------|-------|-------|-------|-------|----------
 *  WDTINT | WINDOW1 | WINDOW0 | WDTON | WDCS2 | WDCS1 | WDCS0 | WDSTBYON
 * --------|---------|---------|-------|-------|-------|-------|----------
 */
// <h> WDT Control Option Byte (C0H)
//   <e.4> Enable WDT (WDTON)
//     <o.5..6> Watchdog timer window open period setting      <2=> 75%        <3=> 100%
//     <o.1..3> Watchdog timer overflow time setting           <0=> 2^6/fIL    <1=> 2^7/fIL
//                                                             <2=> 2^8/fIL    <3=> 2^9/fIL
//                                                             <4=> 2^11/fIL   <5=> 2^13/fIL
//                                                             <6=> 2^14/fIL   <7=> 2^16/fIL
//     <e.0>    Operation in Standby mode setting (WDSTBYON)
//              <i> WDT Operaton in SLEEP/DEEPSLEEP mode.
//     </e>
//     <e.7>    interrupt enable
//              <i> interval interrupt is generated when 75% + 1/2 fIL of the overflow time is reached.
//     </e>
//   </e>
// </h>
    0xEF,

/**
 * @brief LVD Control BYTE (C1H)
 * Please refer to the user manual for details.
 *    7   |   6   |   5   |   4   |   3   |   2   |    1    |    0     
 * -------|-------|-------|-------|-------|-------|---------|----------
 *  VPOC2 | VPOC1 | VPOC0 |   1   | LVIS1 | LVIS0 | LVIMDS1 | LVIMDS0
 * -------|-------|-------|-------|-------|-------|---------|----------
 */
// <h> LVD Control Option Byte (C1H)
//     <o.0..7> Voltage detection setting (VLVD)              <0xFF=> ( LVD OFF )
//                                                            <0x3D=> VLVD = 1.88V/1.84V    ( interrupt mode )         
//                                                            <0x39=> VLVD = 1.98V/1.94V    ( interrupt mode )         
//                                                            <0x35=> VLVD = 2.09V/2.04V    ( interrupt mode )         
//                                                            <0x5D=> VLVD = 2.50V/2.45V    ( interrupt mode )         
//                                                            <0x59=> VLVD = 2.61V/2.55V    ( interrupt mode )         
//                                                            <0x55=> VLVD = 2.71V/2.65V    ( interrupt mode )         
//                                                            <0x7D=> VLVD = 2.81V/2.75V    ( interrupt mode )         
//                                                            <0x79=> VLVD = 2.92V/2.86V    ( interrupt mode )         
//                                                            <0x75=> VLVD = 3.02V/2.96V    ( interrupt mode )         
//                                                            <0x3F=> VLVD = 1.88V/1.84V    ( reset mode )             
//                                                            <0x3B=> VLVD = 1.98V/1.94V    ( reset mode )             
//                                                            <0x37=> VLVD = 2.09V/2.04V    ( reset mode )             
//                                                            <0x5F=> VLVD = 2.50V/2.45V    ( reset mode )             
//                                                            <0x5B=> VLVD = 2.61V/2.55V    ( reset mode )             
//                                                            <0x57=> VLVD = 2.71V/2.65V    ( reset mode )             
//                                                            <0x7F=> VLVD = 2.81V/2.75V    ( reset mode )             
//                                                            <0x7B=> VLVD = 2.92V/2.86V    ( reset mode )             
//                                                            <0x77=> VLVD = 3.02V/2.96V    ( reset mode )             
//                                                            <0x3A=> VLVDH = 1.98V/1.94V, VLVDL = 1.84V    ( interrupt & reset mode ) 
//                                                            <0x36=> VLVDH = 2.09V/2.04V, VLVDL = 1.84V    ( interrupt & reset mode ) 
//                                                            <0x32=> VLVDH = 3.13V/3.06V, VLVDL = 1.84V    ( interrupt & reset mode ) 
//                                                            <0x5A=> VLVDH = 2.61V/2.55V, VLVDL = 2.45V    ( interrupt & reset mode ) 
//                                                            <0x56=> VLVDH = 2.71V/2.65V, VLVDL = 2.45V    ( interrupt & reset mode ) 
//                                                            <0x52=> VLVDH = 3.75V/3.67V, VLVDL = 2.45V    ( interrupt & reset mode ) 
//                                                            <0x7A=> VLVDH = 2.92V/2.86V, VLVDL = 2.75V    ( interrupt & reset mode ) 
//                                                            <0x76=> VLVDH = 3.02V/2.96V, VLVDL = 2.75V    ( interrupt & reset mode ) 
//                                                            <0x72=> VLVDH = 4.06V/3.98V, VLVDL = 2.75V    ( interrupt & reset mode ) 
//              <i> Please setting the item for interrupt & reset mode
// </h>
    0xFF,

/**
 * @brief HOCO Control BYTE (FRQSEL)
 * Please refer to the user manual for details.
 *    7   |   6   |   5   |    4    |    3    |    2    |    1    |    0    
 * -------|-------|-------|---------|---------|---------|---------|---------
 *    1   |   1   |   1   | FRQSEL4 | FRQSEL3 | FRQSEL2 | FRQSEL1 | FRQSEL0 
 * -------|-------|-------|---------|---------|---------|---------|---------
 */
// <h> HOCO Control Option Byte (C2H)
//   <o.0..4> High-speed OCO clock setting                  <0xE8=> fHOCO = 64MHz, fIH = 64MHz
//                                                          <0xE0=> fHOCO = 48MHz, fIH = 48MHz
//                                                          <0xE9=> fHOCO = 64MHz, fIH = 32MHz
//                                                          <0xE1=> fHOCO = 48MHz, fIH = 24MHz
//                                                          <0xEA=> fHOCO = 64MHz, fIH = 16MHz
//                                                          <0xE2=> fHOCO = 48MHz, fIH = 12MHz
//                                                          <0xEB=> fHOCO = 64MHz, fIH =  8MHz
//                                                          <0xE3=> fHOCO = 48MHz, fIH =  6MHz
//                                                          <0xEC=> fHOCO = 64MHz, fIH =  4MHz
//                                                          <0xE4=> fHOCO = 48MHz, fIH =  3MHz
//                                                          <0xED=> fHOCO = 64MHz, fIH =  2MHz
// </h>
    0xEA, 

/**
 * @brief Flash Protect Control BYTE
 * Please refer to the user manual for details.
 */
// <h> OCD Control Option Byte (C3H)
//   <o.0..7> On-chip debug setting (OCDEN)                 <0xFF=> Enable  <0xC3=> Disable
//            <i> OCDM(500004H) == 0x3C && OCDEN == 0xC3: Debugger can not erease/write/read Flash.
//            <i> OCDM(500004H) != 0x3C && OCDEN == 0xC3: Debugger can only chip erease Flash but cannot write/read Flash.
// </h>
    0xFF

};
  • 中微的写法给到了上面,似乎没啥特别。使用const关键词将内容定义到FLASH存储区,4个字节大小对应字节选项,中微也给其中的每一位作了详细解释。可是这是如何精准的映射到000C0H~000C3H这四个地址之中的呢?
const uint8_t user_opt_data[4] __attribute__((used)) __attribute__((section(".ARM.__AT_0x000000C0"))) =
  • 我们看到在定义时还加了额外的东西 使用了__attribute__((used)) 这个关键词,后面指定section区域,放置在名叫.ARM.__AT_0x000000C0这个地方。
  • attribute()是GNU C的一种机制,编译时可对函数、变量进行一些设置。更多描述可见该文章:点击此处
    在这里插入图片描述
  • 打开我们的.map文件,搜索 .ARM.__AT_0x000000C0 我们发现在目标文件中确实存在着这么一个区域地址映射到了0x000000C0上,大小为4个字节。
  • 到这里我们就大概明白了,只需修改该数组中变量的值,就能设置芯片的看门狗、LVD、以及系统时钟,没有太多的繁琐步骤。

5、main()函数

  • 这个时候再看我们的主函数,通过前面的配置获取实际的系统运行频率,再配置了1ms的systick中断。
int main()
{
	uint32_t msCnt; 	// count value of 1ms
	
	SystemCoreClockUpdate();
	msCnt = SystemCoreClock / 1000;
	SysTick_Config(msCnt); 

	while(1)
	{
	
	}
}

四、其它

  • 至此,我们清楚了CMS32L051这颗芯片在初始化时对内部到底作了哪些操作。接下来,我会逐步分享一些该芯片的其它相关demo。

!!!本文为欢喜6666在CSDN原创发布,复制或转载请注明出处:)!!!

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
CMS32L051是一款低功耗、高性能的ARM Cortex-M0+内核微控制器。它具有丰富的外设和功能,适用于各种嵌入式应用场景。以下是一些关于CMS32L051学习笔记的介绍: 1. 硬件介绍:CMS32L051微控制器具有32位ARM Cortex-M0+内核,工作频率可达到50MHz。它包含了多个外设,如通用串行接口、通用定时器、模拟比较器等,可以满足各种应用需求。 2. 开发环境:为了进行CMS32L051的开发,你可以使用Keil MDK开发环境或者其他支持ARM Cortex-M系列的开发工具。Keil MDK提供了一套完整的开发工具链,包括编译器、调试器和仿真器,方便进行代码编写、调试和下载。 3. 编程语言:CMS32L051可以使用C语言进行编程。你可以通过编写C语言代码来控制微控制器的各个外设,并实现所需的功能。 4. 外设编程:CMS32L051具有丰富的外设,包括GPIO、UART、SPI、I2C等。你可以学习如何初始化和配置这些外设,并使用相应的库函数进行数据的读写和控制。 5. 中断处理:中断是嵌入式系统中常用的一种事件处理机制。你可以学习如何配置和处理CMS32L051的中断,以实现对外部事件的响应和处理。 6. 低功耗设计:CMS32L051具有低功耗特性,适用于电池供电的应用场景。你可以学习如何进行低功耗设计,包括使用低功耗模式、优化代码和外设的使用等。 7. 调试技巧:在开发过程中,调试是非常重要的一环。你可以学习如何使用调试器和仿真器进行代码的单步调试、变量查看和性能分析,以提高开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值