Giter VIP home page Giter VIP logo

stm32l0xx_hal_driver's Introduction

STM32CubeL0 HAL Driver MCU Component

latest tag

Overview

STM32Cube is an STMicroelectronics original initiative to ease developers' life by reducing efforts, time and cost.

STM32Cube covers the overall STM32 products portfolio. It includes a comprehensive embedded software platform delivered for each STM32 series.

  • The CMSIS modules (core and device) corresponding to the ARM(tm) core implemented in this STM32 product.
  • The STM32 HAL-LL drivers, an abstraction layer offering a set of APIs ensuring maximized portability across the STM32 portfolio.
  • The BSP drivers of each evaluation, demonstration or nucleo board provided for this STM32 series.
  • A consistent set of middleware libraries such as RTOS, USB, FatFS, graphics, touch sensing library...
  • A full set of software projects (basic examples, applications, and demonstrations) for each board provided for this STM32 series.

Two models of publication are proposed for the STM32Cube embedded software:

  • The monolithic MCU Package: all STM32Cube software modules of one STM32 series are present (Drivers, Middleware, Projects, Utilities) in the repository (usual name STM32Cubexx, xx corresponding to the STM32 series).
  • The MCU component: each STM32Cube software module being part of the STM32Cube MCU Package, is delivered as an individual repository, allowing the user to select and get only the required software functions.

Description

This stm32l0xx_hal_driver MCU component repo is one element of the STM32CubeL0 MCU embedded software package, providing the HAL-LL Drivers part.

Release note

Details about the content of this release are available in the release note here.

Compatibility information

It is crucial that you use a consistent set of versions for the CMSIS Core - CMSIS Device - HAL, as mentioned in this release note.

The full STM32CubeL0 MCU package is available here.

Troubleshooting

If you have any issue with the software content of this repository, you can file an issue here.

For any other question related to the product, the tools, the environment, you can submit a topic on the ST Community/STM32 MCUs forum.

stm32l0xx_hal_driver's People

Contributors

alabstm avatar aselstm avatar hbostm avatar rjmstm avatar rkoustm avatar tounstm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stm32l0xx_hal_driver's Issues

Missing parenthesis in LL_MPU_ConfigRegion

In function LL_MPU_ConfigRegion() from stm32l0xx_ll_cortex.h the following line:
WRITE_REG(MPU->RASR, (MPU_RASR_ENABLE_Msk | Attributes | SubRegionDisable << MPU_RASR_SRD_Pos));

should be fixed with:
WRITE_REG(MPU->RASR, (MPU_RASR_ENABLE_Msk | Attributes | (SubRegionDisable << MPU_RASR_SRD_Pos)));

which is the correct implementation already present in other STM32 MCU HAL drivers.

HAL_ADC_Start_DMA() misleading param description

HAL_ADC_Start_DMA() method, the last Length param description reads:

* @param Length Number of data to be transferred from ADC peripheral to memory

This is misleading. Param name and the description suggests data buffer length (bytes?) is required while number of conversions is expected.

This value is finally used to set hdma->Instance->CNDTR register (DMA channel x number of data to transfer register).
According to docs "It is decremented after each single DMA ‘read followed by write’ transfer, indicating the remaining amount of data items to transfer."

I think HAL_DMA_Start_IT() and DMA_SetConfig() methods suffer from a similar documentation ambiguity. DataLength param name is used while DataLength is not same as amount of data items. DataLength suggest number of bytes while number of data items (count) is expected.

As far as I can tell, the problem exists in all HAL packages.
HAL param names do not seem to use very consistent naming. Size and Length words are used interchangeably.
In this case Count word would probably be a much better choice.

An I2C NACK during memory address transfer goes undetected.

Dear @ALABSTM,

It seems you released a new HAL with a fix for #1, great! 👍
I do have another bug to report, however:

Set-up

  • Board: B-L072Z-LRWAN
  • Toolchain: arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 9-2019-q4-major)

Description
When a NACK is observed during memory address transfer, it goes undetected until the next I2C transaction, and the I2C HAL produces a HAL_I2C_ERROR_TIMEOUT error rather than a HAL_I2C_ERROR_AF error.

We have observed a situation in which a I2C slave device NACK's a memory address (see sreenshot 1 below). However it seems the I2C hal cannot cope with this situation. When this occurs, the I2C driver is waiting for the TC bit to high in case a of a MemoryRead operation:

stm32l0xx_hal_i2c.c:5266:

  /* Wait until TC flag is set */
  if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, RESET, Timeout, Tickstart) != HAL_OK)
  {
    return HAL_ERROR;
  }

However, since the NACK occurs this operation times out. If we inspect the I2C peripheral register contents when this occurs, we observe:

 CR1 = 0x1,
 CR2 = 0x10032,
 OAR1 = 0x8000,
 OAR2 = 0x0,
 TIMINGR = 0xd61329,
 TIMEOUTR = 0x0,
 ISR = 0x131,           # Bit 8: BERR = 1 (Bus error), Bit 5: STOPF = 1 (Stop detected), Bit 4: NACKF = 1 (Not Acknowledge received), Bit 1: TXE = 1 (Transmit data register empty )
 ICR = 0x0,
 PECR = 0x0,
 RXDR = 0x3c,
 TXDR = 0x37

But we don't notice any of that because the I2C HAL doesn't check for that NACKF anymore, we just observe a timeout and we get on with our business, but the next time we request an I2C read transaction the following occurs: the HAL I2C driver requests a memory read with I2C_RequestMemoryRead() wherein the transaction is initiated by configuring the transfer and generating a start condition, after which the driver waits for the Transmit interrupt status bit to become set (TXIS). In the subroutine responsible for this the NACKF status bit does get tested:

stm32l0xx_hal_i2c.c:6256:

static HAL_StatusTypeDef I2C_WaitOnTXISFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
{
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == RESET)
  {
    /* Check if a NACK is detected */
    if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK)
    {
      return HAL_ERROR;
    }
    // ...

Since the NACKF is still set from the previous I2C transaction, this new I2C transaction will be prematurely aborted, while the start condition and slave address will already be transmitted on the wire. If we inspect the register contents if has happened we observe:

  CR1 = 0x1,
  CR2 = 0x0,
  OAR1 = 0x8000,
  OAR2 = 0x0,
  TIMINGR = 0xd61329,
  TIMEOUTR = 0x0,
  ISR = 0x8141,       # Bit 15: BUSY = 1 (Busy), Bit 8: BERR = 1 (Bus error), Bit 6: TC = 1 (Transfer Complete), Bit 1: TXE = 1 (Transmit data register empty)
 ICR = 0x0,
  ICR = 0x0,
  PECR = 0x0,
  RXDR = 0x0,
  TXDR = 0x0

Since the NACK was already detected during previous I2C transaction the STOP condition was already generated during previous I2C transaction (see register contents above). But now the current I2C transaction is prematurely aborted, in combination with the fact that the START condition and the I2C device address has already been transmitted on the wire, the BUSY flag is set high! Which prevents any further I2C transactions to be request from the HAL. This will generate timeout issues at each subsequent i2c_mem_read request:

stm32l0xx_hal_i2c.c:2450:

    if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK)
    {
      return HAL_ERROR;
    }

So I propose to please add a NACKF detection to memory address transfer phase as well, either by adding an additional call to I2C_WaitOnTXISFlagUntilTimeout() or by extending the I2C_WaitOnFlagUntilTimeout() function with a test for NACKF.

What do you think is best?

Thanks,
Best regards,

Jelle De Vleeschouwer

Screenshots

nack_received

Improper EXTI reset in HAL_GPIO_DeInit()

Dear @ALABSTM,

TL;DR

The HAL_GPIO_DeInit() contains a bug related to the order in which GPIO configuration and EXTI configuration is reset to its "reset defaults". The issue seems not to be present in other HAL drivers, such as for example in stm32f4xx_hal_driver. In those HAL drivers, disabling the EXTI interrupt comes before resetting the GPIO configuration as it should be.

Scenario

Let's assume you have an active low switch (switch with external pull-up) connected to a GPIO pin and one would like to trigger an EXTI interrupt on the falling edge when closing that switch. But, in the meantime (since number of GPIO pins is limited), that GPIO is shared with another hardware resource. In rest, the GPIO is configured for that latter/second resource. One would typically see the following scenario to switch to input with EXTI interrupt on falling edge:

  1. Reconfigure the GPIO for EXTI with GPIO_MODE_IT_FALLING and all boiler plate code using GPIO_Init().
  2. Wait for the EXTI interrupt to fire or timeout
  3. Restore GPIO configuration to map on that second hardware resource with GPIO_Init().

Problem

In the scenario above, when that hardware resource is for example an output and the output isn't driven, the EXTI interrupt might fire since a '1'-to-'0' transition is observed on the EXTI line and that EXTI interrupt is still enabled.

Cause

The only way to clear EXTI configuration is by using HAL_GPIO_DeInit()

Solution

Use HAL_GPIO_DeInit() to clear EXTI configuration to reset defaults.

Follow-up problem 1

The solution for the problem causes another problem: in HAL_GPIO_DeInit() the I/O mode is reset to analog high impedance before the EXTI is disabled!

GPIOx->MODER |= (GPIO_MODER_MODE0 << (position * 2U));
/* Configure the default Alternate Function in current IO */
GPIOx->AFR[position >> 3U] &= ~((uint32_t)0xFU << ((uint32_t)(position & (uint32_t)0x07U) * 4U)) ;
/* Configure the default value for IO Speed */
GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEED0 << (position * 2U));
/* Configure the default value IO Output Type */
GPIOx->OTYPER &= ~(GPIO_OTYPER_OT_0 << position) ;
/* Deactivate the Pull-up oand Pull-down resistor for the current IO */
GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPD0 << (position * 2U));
/*------------------------- EXTI Mode Configuration --------------------*/
/* Clear the External Interrupt or Event for the current IO */
tmp = SYSCFG->EXTICR[position >> 2U];
tmp &= (((uint32_t)0x0FU) << (4U * (position & 0x03U)));
if(tmp == (GPIO_GET_INDEX(GPIOx) << (4U * (position & 0x03U))))
{
tmp = ((uint32_t)0x0FU) << (4U * (position & 0x03U));
SYSCFG->EXTICR[position >> 2U] &= ~tmp;
/* Clear EXTI line configuration */
EXTI->IMR &= ~((uint32_t)iocurrent);

The GPIO analog high impedance configuration disables the internal TTL Schmitt trigger producing a '0' on its ouput (See Figure 26 on page 242 in RM0376). Again, a '1'-to-'0' transition is observed on the EXTI line and that EXTI interrupt is still enabled. The EXTI interrupt will fire again.

Cause

The code block responsible for resetting the I/O mode of the GPIO comes before the code block responsible for resetting the EXTI configuration.

Solution

Swap the two code blocks in HAL_GPIO_DeInit() around.

Follow-up problem 2

There is still another problem in the code block responsible for resetting the EXTI configuration itself: the line multiplexer is reset before the EXTI is masked! This means that somehow the input data on GPIOA is '0', again a '1'-to-'0' transition is observed on the EXTI line and that EXTI interrupt is still enabled. The EXTI interrupt will fire again.

Cause

The code resetting the EXTI line multiplexer:

tmp = ((uint32_t)0x0FU) << (4U * (position & 0x03U));
SYSCFG->EXTICR[position >> 2U] &= ~tmp;

comes before the code resetting the EXTI interrupt masks:
/* Clear EXTI line configuration */
EXTI->IMR &= ~((uint32_t)iocurrent);
EXTI->EMR &= ~((uint32_t)iocurrent);
/* Clear Rising Falling edge configuration */
EXTI->RTSR &= ~((uint32_t)iocurrent);
EXTI->FTSR &= ~((uint32_t)iocurrent);

Solution

Swap the two code blocks around.

What do you think? Could you please take a look at this?

Thanks,
Best regards,

Jelle De Vleeschouwer

ADC External Trigger Conversion Sources Incorrect for Category 1 Devices

Using custom board with STM32L011F3P3.
IDE is Keil MDK Version 5.38 with ST32CubeMX version 6.9.1.

The STM32L0xx reference manual (Feb 2022) states on page 281, that the TIM21_TRGO trigger is only available on Category 1 devices, which is defined on page 47 as the STM32L011x and STM32L021x devices.

CubeMX does not allow setting the ADC external trigger conversion source as TIM21_TRGO. Upon inspection of the HAL driver (stm32l0xx_hal_adc_ex.h, line 68) it is coded to only allow TIM21_TRGO on Cat. 2, 3, and 5 devices (all except Cat. 1).

To determine if the reference manual or the HAL driver was wrong, I manually set the external trigger to TIM21_TRGO (hadc.Init.ExternalTrigConv = ADC_CFGR1_EXTSEL_2;) per ref. manual page 281. Debugging the code I verified the callback, HAL_ADC_ConvCpltCallback(), was being fired and the debug output pin was being toggled in the center of each pulse width of the PWM output as expected. See code snippets below. Screenshots of CubeMX config, HAL driver, ref. manual are attached for reference.

// top of main.c...
HAL_TIM_Base_Start_IT(&htim21);
HAL_TIM_PWM_Start_IT(&htim21, TIM_CHANNEL_1);
HAL_ADC_Start_IT(&hadc);

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
adcVal = HAL_ADC_GetValue(hadc);
HAL_GPIO_TogglePin(DEBUG_OUT_GPIO_Port, DEBUG_OUT_Pin);
}

RefManual_ADC_ExtTrigConv_Sources

RefManual_Device_Categories

ST32CubeMX_ADC_Config

ST32CubeMX_TIM21_Config

stm32l0xx_hal_adc_ex_BUG

I2C Slave mode problem while receiving data - buffer overrun

While implementing I2C slave mode solution presented in I2C_TwoBoards_RestartAdvComIT official example and the one described here and here I noticed that calling HAL_I2C_Slave_Seq_Receive_IT() may cause buffer overrun leading to unpredictable behavior including program crash. In brief, received byte value is stored twice at two consecutive addresses.
Here is the detailed call sequence when receiving the last frame (pseudocode):

-> HAL_I2C_EV_IRQHandler();
   -> I2C_Slave_ISR_IT();
      -> I2C_ITSlaveCplt();
         // problem 1: I2C_FLAG_RXNE flag is cleared but on local/temp flags copy only
         tmpITFlags &= ~I2C_FLAG_RXNE;
         *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->RXDR;
         pBuffPtr++;
         -> I2C_ITSlaveSeqCplt();
            -> HAL_I2C_SlaveRxCpltCallback();
               // problem 2: HAL_I2C_Slave_Seq_Receive_IT is called when it is already known that there is no more data 
               -> HAL_I2C_Slave_Seq_Receive_IT(Size=1)
                  hi2c->XferCount = Size; // here XferCount is set to 1 again while receiving of the current frame is not finished
	    <- HAL_I2C_SlaveRxCpltCallback();
         <- I2C_ITSlaveSeqCplt();
      <- I2C_ITSlaveCplt();
   <- I2C_Slave_ISR_IT();
      // problem 3: data from RXDR register is stored again in buffer at next position (buffer pointer previously increased) without checking that I2C_FLAG_RXNE flag is still set
      if (hi2c->XferCount > 0U) *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->RXDR;
<- HAL_I2C_EV_IRQHandler();

2C_NEXT_FRAME and I2C_FIRST_FRAME flags appear to be equivalent - I found no difference in HAL code, both values are checked everywhere.

Package: STM32Cube_FW_L0_V1.12.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.