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

本文详细介绍了一款国产32位MCU——CMS32L051的初始化过程,包括启动文件、SystemInit()函数、时钟配置等关键步骤,并解析了代码配置的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

最近使用一款国产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在优快云原创发布,复制或转载请注明出处:)!!!

CMS32L051LQ32是款来自瑞萨电子(Renesas)的微控制器,通常用于低功耗、嵌入式应用。为了使用其内置的库函数并完成初始化,你需要遵循以下般步骤: 1. **包含头文件**: 首先,在C源文件的顶部,添加CMS32L051LQ32库相关的头文件,如`<Renesas_CMS32Lxx.h>`或具体的设备驱动头文件。 ```c #include "Renesas_CMS32L051LQ32.h" ``` 2. **定义宏和配置**: CMS32L051LQ32支持多种配置选项,例如时钟频率、外设功能等。你需要根据项目需求设置相应的预处理器宏。例如,如果你要启用UART通信,可能会这样配置: ```c #define CMS32L_UART_ENABLE #define CMS32L_UART_BAUD_RATE (9600) ``` 3. **初始化硬件**: 使用库提供的函数初始化CMS32L051LQ32的硬件资源。比如,初始化UART: ```c void initialize_uart(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 打开USART1时钟 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = CMS32L_UART_BAUD_RATE; // 设置波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); // 启动串口 } ``` 4. **启动库函数**: 根据库的具体文档,可能需要调用某个函数来激活或初始化整个库服务。 ```c void start_library_service() { // CMS32L051LQ32_Library_Init(); // 如果有对应的初始化函数 } ``` 5. **清理和关闭**: 当不再需要该功能时,记得释放资源并关闭硬件: ```c void finalize_uart(void) { USART_DeInit(USART1); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, DISABLE); // 关闭USART1时钟 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值