Author Topic: Starting with STM32 (NUCLEO-L412KB)  (Read 10893 times)

0 Members and 1 Guest are viewing this topic.

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #50 on: May 16, 2024, 04:02:49 pm »
The advantage of HAL libraries is that you don't have to debug your own code.

Attached is the improved code after removing a bug in usart routines.

« Last Edit: May 16, 2024, 05:32:45 pm by Picuino »
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3913
  • Country: nl
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #51 on: May 16, 2024, 05:55:42 pm »
The advantage of HAL libraries is that you don't have to debug your own code.

The disadvantage is that you have to debug someone else's code.  :-DD

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #52 on: May 16, 2024, 06:04:54 pm »
Yes, you are right.

The advantage of all this is that I have been able to test the STM32 debugging system and it is quite good. You can even see the assembler instructions.

On another subject, I tried to make a microsecond delay routine and it was almost impossible to get the times I wanted. If I set the loop counter to a low amount (16), the assembler becomes a series of instructions in a row with no loop and takes a short time. If I set a higher amount to the loop counter (20) then the loop does execute and takes too long.
I don't know how to tell the compiler not to optimize that piece of code, to get a stable timming:

Code: [Select]
void delay_us(uint16_t delay) {
    register uint16_t cycles;
    while (delay--) {
        cycles = 20;
        while (cycles--) {
            __asm__ __volatile__("");
        }
    }
}
« Last Edit: May 16, 2024, 06:06:46 pm by Picuino »
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #53 on: May 16, 2024, 06:13:55 pm »
I have already tested the operation of the interrupts and the ADC, which works correctly.

Now it is time to move on to handling the DMA to capture data from the ADC to memory.
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3913
  • Country: nl
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #54 on: May 16, 2024, 06:22:43 pm »
Yes, you are right.

The advantage of all this is that I have been able to test the STM32 debugging system and it is quite good. You can even see the assembler instructions.

On another subject, I tried to make a microsecond delay routine and it was almost impossible to get the times I wanted. If I set the loop counter to a low amount (16), the assembler becomes a series of instructions in a row with no loop and takes a short time. If I set a higher amount to the loop counter (20) then the loop does execute and takes too long.
I don't know how to tell the compiler not to optimize that piece of code, to get a stable timming:

Code: [Select]
void delay_us(uint16_t delay) {
    register uint16_t cycles;
    while (delay--) {
        cycles = 20;
        while (cycles--) {
            __asm__ __volatile__("");
        }
    }
}

To get this more or less right you can use inline assembler.

Code: [Select]
  uint32 loops = usec * 54;

  __asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n"  "bne 1b":"=r"(loops):"0"(loops));

I use the above in my scope project and might not be valid for the STM32L412 due to it probably using thumb instructions, but the idea of passing parameters will be the same.

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #55 on: May 16, 2024, 06:43:57 pm »
You have given me a good idea. This code works, except for the value 1 which, I don't know why, produces no delay.


Code: [Select]
void delay_us(uint16_t delay) {
    delay *= 16;
    while (delay--) {
        __asm__ __volatile__("");
    }
}

EDIT:
That kind of inline assembler seems cryptic to me. I don't understand it. If at some point I have to do some function in assembler, I hope to be able to do it another way.

I would prefer this other way: https://community.st.com/t5/stm32cubeide-mcus/how-to-run-assembly-code-in-stm32-cube-ide-nucleo-f446re/td-p/139119
« Last Edit: May 16, 2024, 06:48:08 pm by Picuino »
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #56 on: May 16, 2024, 06:53:00 pm »
Code: [Select]
__asm__ __volatile__ (
   "1:\n"
   "subs %0, %1, #1\n"
   "bne 1b"
   :"=r"
   (loops)
   :"0"
   (loops)
);

What value do %0 and %1 take?

What is "=r"?

EDIT:
* http://www.ethernut.de/en/documents/arm-inline-asm.html
* https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
* https://gcc.gnu.org/onlinedocs/gcc/extensions-to-the-c-language-family/how-to-use-inline-assembly-language-in-c-code.html
« Last Edit: May 17, 2024, 07:06:32 am by Picuino »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14662
  • Country: fr
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #57 on: May 16, 2024, 10:04:48 pm »
The advantage of HAL libraries is that you don't have to debug your own code.

The disadvantage is that you have to debug someone else's code.  :-DD

Exactly. The advantage of using vendor HALs IMO is definitely, and absolutely not that.
It's getting started in a much shorter amount of time (usually), and having reasonable portability between MCUs of the same series, or even among different series of the same vendor. Which is a plus.

If you don't care about those points or can afford not to care, then they are just a waste of time, especially in the long run. And in some fields, having to deal with third-party code that doesn't follow your own set of rules is also a problem.

At least, with ST, the HAL is entirely provided as source code, so you can audit it. They claim compliance with MISRA, which is supposed to (at least partially) adress my last point above, but they comply in a way that makes the code very bloated and not pretty to read. So, yeah.
 

Online dietert1

  • Super Contributor
  • ***
  • Posts: 2174
  • Country: br
    • CADT Homepage
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #58 on: May 16, 2024, 11:04:36 pm »
Probably there has been some development going on and STM32 Cube improved in comparison to the first years. If you search the web for HAL problems, a lot of the threads in their online forum date from 2017 or 2018.
When i look into HAL sources, most of the time it happens in order to avoid searching the MCU reference manual. It's something nice to have.

Regards, Dieter
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3913
  • Country: nl
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #59 on: May 17, 2024, 05:40:28 am »
Code: [Select]
__asm__ __volatile__ (
   "1:\n"
   "subs %0, %1, #1\n"
   "bne 1b"
   :"=r"
   (loops)
   :"0"
   (loops)
);

What value do %0 and %1 take?

What is "=r"?

EDIT:
http://www.ethernut.de/en/documents/arm-inline-asm.html

Ah you found the manual. I wrote that code based on an example and did not look into it that deep. Needed it working fast and it did. Never looked back on it.  :)

Most of the time I don't need inline assembler.

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3913
  • Country: nl
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #60 on: May 17, 2024, 05:46:07 am »
Probably there has been some development going on and STM32 Cube improved in comparison to the first years. If you search the web for HAL problems, a lot of the threads in their online forum date from 2017 or 2018.
When i look into HAL sources, most of the time it happens in order to avoid searching the MCU reference manual. It's something nice to have.

Regards, Dieter

I did play with it in the beginning and most of the things I tried (USB related) did not work. Searching through the code is a drag. I rather read the reference manual, even though they are not always that easy to grasp either. So maybe it improved by now, but I got used to doing it bare metal and don't need the portability of it either.

Online dietert1

  • Super Contributor
  • ***
  • Posts: 2174
  • Country: br
    • CADT Homepage
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #61 on: May 17, 2024, 07:50:30 am »
Last year i got the USB stack working for CDC within some hours after using CubeMX to prepare everything. The only mod i did some days later was a few lines of C to provide re-enumeration at each debugger launch. Something described in the web. Otherwise one had to pull and re-insert the plug each time.
That USB solution has been working flawlessly since then.

Regards, Dieter
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3913
  • Country: nl
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #62 on: May 17, 2024, 08:42:02 am »
Last year i got the USB stack working for CDC within some hours after using CubeMX to prepare everything. The only mod i did some days later was a few lines of C to provide re-enumeration at each debugger launch. Something described in the web. Otherwise one had to pull and re-insert the plug each time.
That USB solution has been working flawlessly since then.

Regards, Dieter

Ah well, I wrote my own USB implementation and use that for my projects. Even wrote my own Linux driver for a specific application. Interesting learning experiences.

USB does not like interruptions, that is for sure. Found that you can't debug the USB driver code as it will kill the connection every time you halt it. Used wireshark on the host PC to do the development.

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #63 on: May 17, 2024, 02:56:49 pm »
Could someone please let me have a very simple example of how to run the ADC with DMA?
My example does not work.

Code: [Select]
/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <ctype.h>
#include <uart.h>
#include "adc.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC1_Init(void);
/* USER CODE BEGIN PFP */

void blink_led(void);
void blink_PA3(uint16_t microseconds);
void delay_us(uint16_t delay);

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void) {

    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART2_UART_Init();
    MX_ADC1_Init();
    /* USER CODE BEGIN 2 */

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */

    uint16_t adc_buf[1024];
   
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc_buf, 512);

    while (1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */

        // printf("ADC=%d\r\n", (int) adc1_read());
        HAL_Delay(1);
        // blink_PA3(10);
    }
    /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

    /** Configure the main internal regulator output voltage
     */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1)
            != HAL_OK) {
        Error_Handler();
    }

    /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 2;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
            | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
        Error_Handler();
    }

    /** Enables the Clock Security System
     */
    HAL_RCC_EnableCSS();
}

/**
 * @brief ADC1 Initialization Function
 * @param None
 * @retval None
 */
static void MX_ADC1_Init(void) {

    /* USER CODE BEGIN ADC1_Init 0 */

    /* USER CODE END ADC1_Init 0 */

    ADC_MultiModeTypeDef multimode = { 0 };
    ADC_ChannelConfTypeDef sConfig = { 0 };

    /* USER CODE BEGIN ADC1_Init 1 */

    /* USER CODE END ADC1_Init 1 */

    /** Common config
     */
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
    hadc1.Init.LowPowerAutoWait = DISABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.NbrOfConversion = 1;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    hadc1.Init.DMAContinuousRequests = ENABLE;
    hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
    hadc1.Init.OversamplingMode = DISABLE;
    if (HAL_ADC_Init(&hadc1) != HAL_OK) {
        Error_Handler();
    }

    /** Configure the ADC multi-mode
     */
    multimode.Mode = ADC_MODE_INDEPENDENT;
    if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK) {
        Error_Handler();
    }

    /** Configure Regular Channel
     */
    sConfig.Channel = ADC_CHANNEL_10;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.Offset = 0;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
        Error_Handler();
    }
    /* USER CODE BEGIN ADC1_Init 2 */

    /* USER CODE END ADC1_Init 2 */

}

/**
 * @brief USART2 Initialization Function
 * @param None
 * @retval None
 */
static void MX_USART2_UART_Init(void) {

    /* USER CODE BEGIN USART2_Init 0 */

    /* USER CODE END USART2_Init 0 */

    /* USER CODE BEGIN USART2_Init 1 */

    /* USER CODE END USART2_Init 1 */
    huart2.Instance = USART2;
    huart2.Init.BaudRate = 115200;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;
    huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
    if (HAL_UART_Init(&huart2) != HAL_OK) {
        Error_Handler();
    }
    /* USER CODE BEGIN USART2_Init 2 */
    uart_init();

    /* USER CODE END USART2_Init 2 */

}

/**
 * Enable DMA controller clock
 */
static void MX_DMA_Init(void) {

    /* DMA controller clock enable */
    __HAL_RCC_DMA1_CLK_ENABLE();

    /* DMA interrupt init */
    /* DMA1_Channel1_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
    /* USER CODE BEGIN MX_GPIO_Init_1 */
    /* USER CODE END MX_GPIO_Init_1 */

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);

    /*Configure GPIO pin : PA3 */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /*Configure GPIO pin : LD3_Pin */
    GPIO_InitStruct.Pin = LD3_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LD3_GPIO_Port, &GPIO_InitStruct);

    /* USER CODE BEGIN MX_GPIO_Init_2 */
    /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

// Called when first half of buffer is filled
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc) {
    GPIOA->BSRR = (1 << 3); // Set PA3 (Pin A2 in the Nucleo board)
}

// Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
    GPIOA->BRR = (1 << 3);  // Reset PA3
}

void blink_PA3(uint16_t microseconds) {
    GPIOA->BSRR = (1 << 3); // Set PA3 (Pin A2 in the Nucleo board)
    delay_us(microseconds);
    GPIOA->BRR = (1 << 3);  // Reset PA3
}

void delay_us(uint16_t delay) {
    delay *= 16;
    while (delay--) {
        __asm__ __volatile__("");
    }
}

void blink_led(void) {
    HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
    HAL_Delay(5000);
    HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
    HAL_Delay(500);
}

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void) {
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1) {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


Init:
Code: [Select]
    uint16_t adc_buf[1024];
   
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc_buf, 512);


Callbacks:
Code: [Select]
// Called when first half of buffer is filled
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc) {
    GPIOA->BSRR = (1 << 3); // Set PA3 (Pin A2 in the Nucleo board)
}

// Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
    GPIOA->BRR = (1 << 3);  // Reset PA3
}
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #64 on: May 17, 2024, 03:22:27 pm »
It turns out that it works, but only once.
Once the buffer is full (even though it is configured as circular) it does not fill up again.


EDIT:
Correction: it was not configured as circulating. :palm:
Now it is and it works all the time.   :)
« Last Edit: May 17, 2024, 03:37:17 pm by Picuino »
 

Offline tellurium

  • Frequent Contributor
  • **
  • Posts: 267
  • Country: ua
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #65 on: May 17, 2024, 08:59:37 pm »
The advantage of all this is that I have been able to test the STM32 debugging system and it is quite good. You can even see the assembler instructions.

Mine impressions are very different. Cube's debugger seldom works reliably for me. Always acting - suddenly jumps around the sources, adds/removes breakpoints, etc etc. On the other hand, it's exciting: you never know what happens next
Open source embedded network library https://github.com/cesanta/mongoose
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 

Offline tellurium

  • Frequent Contributor
  • **
  • Posts: 267
  • Country: ua
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #66 on: May 17, 2024, 09:06:26 pm »
At least, with ST, the HAL is entirely provided as source code, so you can audit it. They claim compliance with MISRA, which is supposed to (at least partially) adress my last point above, but they comply in a way that makes the code very bloated and not pretty to read. So, yeah.

And not just that. Some Cube HAL code is outright buggy - like Ethernet driver.
Open source embedded network library https://github.com/cesanta/mongoose
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 

Online dietert1

  • Super Contributor
  • ***
  • Posts: 2174
  • Country: br
    • CADT Homepage
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #67 on: May 18, 2024, 06:47:28 am »
Which version of the STM32L4 repository are you referring to? Could you tell us one or two of the bugs you found?

Last year i tried to use a W5500 ethernet interface as i had heard about how much work the STM32 ethernet driver gives. But also with the W5500 i had quite some difficulties and it doesn't work until now. Appears like ethernet is a bit difficult, although i also remember implementing a web interface (small html server) on a MSP430 about 15 years ago, based on ENC28J60 and a small library from the web.

Regards, Dieter
« Last Edit: May 18, 2024, 06:58:56 am by dietert1 »
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #68 on: May 18, 2024, 05:27:51 pm »
Now I need to control quick mathematical operations. Multiplication and addition with 16-bit, 32-bit and 64-bit numbers, both with integers and floating point numbers.
I may also need to use iniline assembler to optimize the result.
 

Online gf

  • Super Contributor
  • ***
  • Posts: 1295
  • Country: de
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #69 on: May 18, 2024, 05:32:51 pm »
Now I need to control quick mathematical operations. Multiplication and addition with 16-bit, 32-bit and 64-bit numbers, both with integers and floating point numbers.
I may also need to use iniline assembler to optimize the result.

For your purpose, look at the CMSIS library.
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #70 on: May 18, 2024, 05:46:50 pm »
First attempt, in c:

Code: [Select]
        GPIOA->BSRR = (1 << 3); // Set PA3

        int i;
        uint16_t *org1 = adc1_buff;
        uint16_t *org2 = adc2_buff;
        uint64_t *dst = mac_buff;
        uint32_t mul;
        uint64_t mac = 0;

        for(i=ADC_BUFF_SIZE/2; i; i--) {
            mul = (*org1++) * (*org2++);
            mac += mul;
            *dst++ = mac;
        }

        GPIOA->BRR = (1 << 3);  // Reset PA3

This code takes 138us to execute for a half buffer size = 1000 positions.
This is 138ns/sample compared to 188ns for ADC samples.
For a first attempt it is not bad at all.

Dissasembly:
Code: [Select]
125               GPIOA->BSRR = (1 << 3); // Set PA3
0800078a:   mov.w   r8, #1207959552 @ 0x48000000
131               uint64_t mac = 0;
0800078e:   movs    r2, #0
129               uint64_t *dst = mac_buff;
08000790:   ldr     r4, [pc, #84]   @ (0x80007e8 <main+448>)
128               uint16_t *org2 = adc2_buff;
08000792:   ldr     r6, [pc, #88]   @ (0x80007ec <main+452>)
127               uint16_t *org1 = adc1_buff;
08000794:   ldr     r0, [pc, #88]   @ (0x80007f0 <main+456>)
125               GPIOA->BSRR = (1 << 3); // Set PA3
08000796:   str.w   r5, [r8, #24]
131               uint64_t mac = 0;
0800079a:   mov     r1, r2
134                   mul = (*org1++) * (*org2++);
0800079c:   ldrh.w  r3, [r0], #2
080007a0:   ldrh.w  r12, [r6], #2
080007a4:   mul.w   r3, r12, r3
135                   mac += mul;
080007a8:   adds    r2, r3, r2
136                   *dst++ = mac;
080007aa:   str.w   r2, [r4], #8
135                   mac += mul;
080007ae:   adc.w   r1, r1, r3, asr #31
133               for(i=ADC_BUFF_SIZE/2; i; i--) {
080007b2:   cmp     r0, r7
080007b4:   str.w   r1, [r4, #-4]
080007b8:   bne.n   0x800079c <main+372>
138               GPIOA->BRR = (1 << 3);  // Reset PA3
080007ba:   str.w   r5, [r8, #40]   @ 0x28
« Last Edit: May 18, 2024, 05:55:37 pm by Picuino »
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #71 on: May 18, 2024, 05:52:30 pm »
Now I need to control quick mathematical operations. Multiplication and addition with 16-bit, 32-bit and 64-bit numbers, both with integers and floating point numbers.
I may also need to use iniline assembler to optimize the result.

For your purpose, look at the CMSIS library.

https://arm-software.github.io/CMSIS_6/latest/General/index.html
I can't find the advantage for what I need.
 

Online PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 969
  • Country: 00
    • Picuino web
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #72 on: May 18, 2024, 05:57:56 pm »
Now I need to implement IIR filter to output filtered results.

* AN540: Implementing IIR Digital Filters
   https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ApplicationNotes/ApplicationNotes/00540c.pdf
* https://stackoverflow.com/questions/50588879/how-to-implement-iir-filter-in-c
* https://en.wikipedia.org/wiki/Infinite_impulse_response

Quote from: Wikipedia
IIR vs FIR Advantages and disadvantages:
The main advantage digital IIR filters have over FIR filters is their efficiency in implementation, in order to meet a specification in terms of passband, stopband, ripple, and/or roll-off. Such a set of specifications can be accomplished with a lower order (Q in the above formulae) IIR filter than would be required for an FIR filter meeting the same requirements. If implemented in a signal processor, this implies a correspondingly fewer number of calculations per time step; the computational savings is often of a rather large factor.

On the other hand, FIR filters can be easier to design, for instance, to match a particular frequency response requirement. This is particularly true when the requirement is not one of the usual cases (high-pass, low-pass, notch, etc.) which have been studied and optimized for analog filters. Also FIR filters can be easily made to be linear phase (constant group delay vs frequency)—a property that is not easily met using IIR filters and then only as an approximation (for instance with the Bessel filter). Another issue regarding digital IIR filters is the potential for limit cycle behavior when idle, due to the feedback system in conjunction with quantization.
« Last Edit: May 18, 2024, 06:03:23 pm by Picuino »
 


Offline dave j

  • Regular Contributor
  • *
  • Posts: 131
  • Country: gb
Re: Starting with STM32 (NUCLEO-L412KB)
« Reply #74 on: May 18, 2024, 06:30:05 pm »
I'm not David L Jones. Apparently I actually do have to point this out.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf