[Nucleo-L4R5]学习下用LL库点灯
搭建工程及CoreMark测试L4R5和L496低功耗对比测试
对于官方的STM32开发库,除了主推的HAL库之外还有一个LL(Low Layer)库,在下载的HAL开发包里面HAL库和LL库在一起共存着,LL库更接近硬件层,对于简单的外设可以直接使用,操作类似直接操作寄存器。LL库可以独立使用也可以和HAL一起混合使用,没有接触过的同学可以参考官方的例子,基本包含了各个外设的使用demo。记得前几年刚推出的时候用过一次后来也就没再玩过了,今天再再点个灯熟悉下LL库。外设使用例子LL库的特点是将很多外设的操作都封装成强制内联函数(static inline),这样的好处就是运行的效率更高,类似一种空间换时间的方案。比如在stm32l4xx_ll_bus.h中外设时钟初始化代码如下:__STATIC_INLINE void LL_AHB2_GRP1_EnableClock(uint32_t Periphs)
{
__IO uint32_t tmpreg;
SET_BIT(RCC->AHB2ENR, Periphs);
/* Delay after an RCC peripheral clock enabling */
tmpreg = READ_BIT(RCC->AHB2ENR, Periphs);
(void)tmpreg;
}除了大量的封装在外设头文件(stm32l4xx_ll_xx.h)中内联函数外,LL库对应的外设的模块驱动里面也提供了类似HAL库的初始化函数,但是内部实现还是调用的内联函数。比如下面的的IO口初始化函数ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
uint32_t pinpos = 0x00000000U;
uint32_t currentpin = 0x00000000U;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin));
assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode));
assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull));
/* ------------------------- Configure the port pins ---------------- */
/* Initializepinpos on first pin set */
pinpos = POSITION_VAL(GPIO_InitStruct->Pin);
/* Configure the port pins */
while (((GPIO_InitStruct->Pin) >> pinpos) != 0x00000000U)
{
/* Get current io position */
currentpin = (GPIO_InitStruct->Pin) & (0x00000001U << pinpos);
if (currentpin)
{
/* Pin Mode configuration */
LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode);
if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
{
/* Check Speed mode parameters */
assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed));
/* Speed mode configuration */
LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed);
}
/* Pull-up Pull down resistor configuration*/
LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull);
if (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE)
{
/* Check Alternate parameter */
assert_param(IS_LL_GPIO_ALTERNATE(GPIO_InitStruct->Alternate));
/* Speed mode configuration */
if (POSITION_VAL(currentpin) < 0x00000008U)
{
LL_GPIO_SetAFPin_0_7(GPIOx, currentpin, GPIO_InitStruct->Alternate);
}
else
{
LL_GPIO_SetAFPin_8_15(GPIOx, currentpin, GPIO_InitStruct->Alternate);
}
}
}
pinpos++;
}
if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
{
/* Check Output mode parameters */
assert_param(IS_LL_GPIO_OUTPUT_TYPE(GPIO_InitStruct->OutputType));
/* Output mode configuration*/
LL_GPIO_SetPinOutputType(GPIOx, GPIO_InitStruct->Pin, GPIO_InitStruct->OutputType);
}
return (SUCCESS);
}如果我们只使用LL库封装的内联函数的,只需要在工程里面加入一个 UTILS LL module driver.的C文件,这个文件主要是对应系统时钟的一些处理,其他的设置都可以使用头文件里面封装内联函数实现。1、点灯类似寄存器操作,点灯就是初始化IO口的时钟,然后设置对应的IO输出模式即可,其他的速度和上下拉也可以一步一步设置void LED_Init(void)
{
/* Enable the LED Clock */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_7, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_14, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_7, LL_GPIO_MODE_OUTPUT);
}闪烁LED 如下:都在使用的内联函数void LED_Blinking(void)
{
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_7 | LL_GPIO_PIN_14);
LL_GPIO_TogglePin(GPIOC, LL_GPIO_PIN_7 );
}
2、串口输出熟悉了LED初始化之后再来看下串口的,首先是对应的IO口的初始化LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);
LL_GPIO_SetPinMode(GPIOG, LL_GPIO_PIN_7, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOG, LL_GPIO_PIN_7, LL_GPIO_AF_8);
LL_GPIO_SetPinSpeed(GPIOG, LL_GPIO_PIN_7, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(GPIOG, LL_GPIO_PIN_7, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOG, LL_GPIO_PIN_7, LL_GPIO_PULL_UP);
LL_GPIO_SetPinMode(GPIOG, LL_GPIO_PIN_8, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOG, LL_GPIO_PIN_8, LL_GPIO_AF_8);
LL_GPIO_SetPinSpeed(GPIOG, LL_GPIO_PIN_8, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(GPIOG, LL_GPIO_PIN_8, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOG, LL_GPIO_PIN_8, LL_GPIO_PULL_UP);然后是时钟源的初始化 /* (2) Enable USART peripheral clock and clock source ***********************/
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
LL_PWR_EnableVddIO2();
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
/* HSI configuration and activation */
LL_RCC_HSI_Enable();
while(LL_RCC_HSI_IsReady() != 1)
{
};
/* Set clock source */
LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_HSI);
最后就是串口的的参数设置和使能了 /* TX/RX direction */
LL_LPUART_SetTransferDirection(LPUART1, LL_LPUART_DIRECTION_TX_RX);
/* 8 data bit, 1 start bit, 1 stop bit, no parity */
LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_8B, LL_LPUART_PARITY_NONE, LL_LPUART_STOPBITS_1);
/* No Hardware Flow control */
/* Reset value is LL_USART_HWCONTROL_NONE */
// LL_USART_SetHWFlowCtrl(LPUART1, LL_USART_HWCONTROL_NONE);
/* Set Baudrate to 9600 using HSI frequency set to HSI_VALUE */
LL_LPUART_SetBaudRate(LPUART1, HSI_VALUE,LL_LPUART_PRESCALER_DIV1, 9600);
/* Enable LPUART1 **********************************************************/
LL_LPUART_Enable(LPUART1);大致的套路和寄存器有点类似,想要使用LL库要对外设的各个初始化流程比较熟悉,没有接触过的可以先参考官方提供的例子。最后是mian函数int main(void)
{
SystemClock_Config();
LPUART1_Init();
LED_Init();
while (1)
{
LED_Blinking();
printf("Hi,I am creep!!!\n");
LL_mDelay(1000);
}
}
下载之后可以看到LED闪烁及串口输出如下:
测试代码:
页:
[1]