creep 发表于 2018-1-6 21:30:23

[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]
查看完整版本: [Nucleo-L4R5]学习下用LL库点灯