[National Technology Low Power Series N32L43x Review] 02. Create a template project
[Copy link]
This post was last edited by xld0932 on 2022-6-26 12:14
This article will use the KEIL MDK integrated development environment to create a template project based on the N32L43XRL-STB development board step by step. Through schematic design, the basic functions of the onboard resources LED, KEY, and USART are implemented, and the commonly used Letter-shell is transplanted through USART. The process will be detailed below. There is a debugging problem record at the end of the article for reference.
Create a project
STEP1. Open KEIL MDK integrated development environment software
STEP2. Click on the menu bar Project->New uVision Project...
STEP3. Enter the project file name in the Create New Project window that pops up, select the path where the project file needs to be saved, and click the Save button
STEP4. In the Select Device from Target window that pops up, select the corresponding chip model on the development board: N32L436RB, and then click OK
STEP5. In the pop-up Manage Run-Time Environment window, no operation is required for the time being, just click OK
STEP6. At this point, we have created an empty KEIL project based on the N32L436RB chip. Next, we need to add project files and configure the project.
STEP7. Click the Manage Project Items button on the toolbar to add project files
STEP8. In the Project Items in the Manage Project Items window that pops up, we can modify the Project Targets name, add file groups in Groups, and add the source code in the corresponding group in Files. After the operation is completed, we click OK
STEP9. The added project group and file information are shown in the figure below
STEP10. Next, we continue to click the Options for Target button on the toolbar to configure the project.
STEP11. In the Target, select Use default compiler version5 for ARM Compiler in the Code Generation area and check Use MicroLIB
STEP12. Check Create HEX File in Output so that the HEX burning file can be automatically generated after we compile the project.
STEP13. In C/C++, fill in the two macros N32L43X and USE_STDPERIPH_DRIVER in Define in Preprocessor Symbols, which act on the underlying driver library program of the chip. Then check C99 Mode, which is a personal compilation habit. Select it according to your needs, and then add the include path of the header file in the Include Paths column.
STEP14. Select the debugger in Debug: CMSIS-DAP Debugger, then click the Settings button. Then we will see that the MCU has been detected in the SW Device area (the development board needs to be connected to the computer via USB)
STEP15. Keep the default option settings in Utilities, then click the Settings button, and check Reset and Run in Flash Download in the pop-up window. In this way, after we download the program through KEIL, the chip will automatically reset and run the program. After confirming that the program download algorithm in Programming Algorithm is corresponding, we click OK
STEP16. At this point our complete KEIL project has been created and configured. Next we need to write code, compile, download the program, and run the debugger.
Writing a driver
STEP1. The development board has three color LED lights on board, which are controlled by the three GPIO port pins PA8, PB4 and PB5. From the schematic diagram, we can see that when the GPIO port pin outputs a high level, the corresponding LED light is in the state of lighting, and when the GPIO port pin outputs a low level, the corresponding LED light is in the state of extinguishing; the driver is as follows:
/*******************************************************************************
* @brief * @param
* @retval
* @attention *******************************************************************************/
void LED_Init(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_8;
GPIO_InitStructure.GPIO_Current = GPIO_DC_4mA;
GPIO_InitStructure.GPIO_Pull = GPIO_No_Pull;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, GPIO_PIN_8, Bit_RESET);
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4;
GPIO_InitStructure.GPIO_Current = GPIO_DC_4mA;
GPIO_InitStructure.GPIO_Pull = GPIO_No_Pull;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_PIN_4, Bit_RESET);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_5;
GPIO_InitStructure.GPIO_Current = GPIO_DC_4mA;
GPIO_InitStructure.GPIO_Pull = GPIO_No_Pull;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_PIN_5, Bit_RESET);
TASK_Append(TASK_ID_LED, LED_Toggle, 250);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LED_Toggle(void)
{
#if 0
if(!GPIO_ReadOutputDataBit(GPIOA, GPIO_PIN_8))
{
GPIO_WriteBit(GPIOA, GPIO_PIN_8, Bit_SET);
}
else
{
GPIO_WriteBit(GPIOA, GPIO_PIN_8, Bit_RESET);
}
#else
static uint8_t Index = 0;
switch(Index)
{
case 0:
GPIO_WriteBit(GPIOA, GPIO_PIN_8, Bit_SET);
GPIO_WriteBit(GPIOB, GPIO_PIN_4, Bit_RESET);
GPIO_WriteBit(GPIOB, GPIO_PIN_5, Bit_RESET);
break;
case 1:
GPIO_WriteBit(GPIOA, GPIO_PIN_8, Bit_RESET);
GPIO_WriteBit(GPIOB, GPIO_PIN_4, Bit_SET);
GPIO_WriteBit(GPIOB, GPIO_PIN_5, Bit_RESET);
break;
case 2:
GPIO_WriteBit(GPIOA, GPIO_PIN_8, Bit_RESET);
GPIO_WriteBit(GPIOB, GPIO_PIN_4, Bit_RESET);
GPIO_WriteBit(GPIOB, GPIO_PIN_5, Bit_SET);
break;
default:
break;
}
Index = (Index + 1) % 3;
#endif
}
STEP2. The development board has three user buttons and one WAKEUP button on board. The three user buttons are controlled by the three GPIO port pins PA4, PA5 and PA6. From the schematic diagram, we can see that when a button is pressed, the corresponding button state is connected to GND and is at a low level. Therefore, we need to configure the normal state of these three buttons (the buttons are not pressed) as pull-up input, so that we can determine whether the button is pressed by detecting the level state of the button; the other button is the WAKEUP button, which is connected to the port pin PA0. It can be used as a normal button function or as a It is the wake-up button of MCU in low power mode. When used as a wake-up button, a resistor needs to be connected in series to the ground, and the button is connected to MCU_VDD to wake up the MCU in low power mode with a rising edge. When used as a normal button, I only need to configure this pin as a floating input, because under normal circumstances, this product pin has been pulled to GND by a series resistor, and when pressed, it will be short-circuited to MCU_VCC by the button, thereby judging the state of the button. The recognition levels of the three user buttons here are exactly opposite to those of the WAKEUP button, so you need to pay attention to this when programming. The driver is as follows:
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void KEY_Init(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_0;
GPIO_InitStructure.GPIO_Pull = GPIO_No_Pull;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Input;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
GPIO_InitStructure.GPIO_Pull = GPIO_Pull_Up;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Input;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
TASK_Append(TASK_ID_KEY, KEY_Scan, 10);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void KEY_SubScan(uint8_t *State, uint8_t *Count, uint8_t Value, uint8_t Active, char *Name)
{
if(*State == 0)
{
if(Value == Active) *Count += 1;
else *Count = 0;
if(*Count > 5)
{
*Count = 0; *State = 1;
printf("\r\n%s Pressed", Name);
}
}
else
{
if(Value != Active) *Count += 1;
else *Count = 0;
if(*Count > 5)
{
*Count = 0; *State = 0;
printf("\r\n%s Release", Name);
}
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void KEY_Scan(void)
{
static uint8_t KeyState[4] = {0, 0, 0, 0};
static uint8_t KeyCount[4] = {0, 0, 0, 0};
KEY_SubScan(&KeyState[0], &KeyCount[0], GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_0), Bit_SET, "WAKEUP");
KEY_SubScan(&KeyState[1], &KeyCount[1], GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_4), Bit_RESET, "KEY1 ");
KEY_SubScan(&KeyState[2], &KeyCount[2], GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_5), Bit_RESET, "KEY2 ");
KEY_SubScan(&KeyState[3], &KeyCount[3], GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_6), Bit_RESET, "KEY3 ");
}
STEP3. In addition to the debugging and program downloading functions, the onboard NS-LINK also integrates a virtual serial port. By connecting it to the USART of the MCU, we can print out some required information to the PC. From the schematic diagram, we can see that the USART1 of the MCU can be connected to the TTL serial port of the NS-LINK by means of a jumper cap. In addition, based on the USART, we have also transplanted the open source code Letter-shell, and the driver is as follows:
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void shellPortWrite(const char ch)
{
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXDE) == RESET);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void shellPortInit(void)
{
GPIO_InitType GPIO_InitStructure;
NVIC_InitType NVIC_InitStructure;
USART_InitType USART_InitStructure;
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF4_USART1;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.GPIO_Pull = GPIO_Pull_Up;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF4_USART1;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
USART_StructInit(&USART_InitStructure);
USART_InitStructure.BaudRate = 115200;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
USART_Init(USART1, &USART_InitStructure);
USART_ClrFlag(USART1, USART_FLAG_RXDNE);
USART_ConfigInt(USART1, USART_INT_RXDNE, ENABLE);
USART_Enable(USART1, ENABLE);
shell.write = shellPortWrite;
shellInit(&shell);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void USART1_IRQHandler(void)
{
if(USART_GetIntStatus(USART1, USART_INT_RXDNE) != RESET)
{
shellHandler(&shell, USART_ReceiveData(USART1));
USART_ClrIntPendingBit(USART1, USART_INT_RXDNE);
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXDE) == RESET);
return ch;
}
Compile, download, debug and run
STEP1. After we have completed the driver program, click the Built or Rebuild button on the toolbar to compile the project source code and confirm that it is correct.
STEP2. Click the Download button on the toolbar or press the F8 shortcut key to burn the program to the chip
STEP3. Open the PC serial debugging software MobaXterm for monitoring. After the code starts running, we see the LED on the development board start flashing, and the serial software prints out messages. At the same time, every time we press a key, we will see the corresponding print message on the serial terminal software, as shown below:
Debugging Issues
After getting the development board, there is no jumper cap short-circuited for RESET in J5 interface. Even if the Reset and Run function is configured in KEIL, it only resets the chip by software reset, and does not actually operate the RESET process of the chip. Therefore, when J5 RESET is not connected, USART prints abnormally after the chip is powered on, as shown in the figure below; I once thought it was a problem with NS-LINK or the chip reset power-on timing, but when I pressed the onboard RESET button independently, the program was normal... So after connecting the oscilloscope to RESET to view the waveform, there was no reset level timing, so I located the RESET jumper cap of J5... After connecting the RESET jumper cap of J5, the program ran normally!!!
Normal power-on printing:
Abnormal power-on printing:
appendix:
Software engineering source code:
Project.zip
(476.74 KB, downloads: 6)
Operation effect:
|