First success with the libopencm3 library

Obvious, the first thing to try using both a new board and a new library is to blink a LED. But there were a couple of issues.

1. The first thing I had to solve, was properly setting the clock of my board in order to have a functional microseconds delay function. The libopencm3_examples project does not come with examples for Nucleo L152RE board and the examples for the STM32L1 Discovery board weren’t too helpful but looking inside the library, I found a set of clock settings for few cases involving STM boards.

2. The second thing was to prepare a correct linker script – the one included in ST Microelectronics STM32L1 driver for this board had external references that does not exist in libopencm3 library and I’m in no way an expert in linker scripts. Fortunately, looking at the included examples, all I had to do was specifying the dimensions and the starting address for the microcontroller memories. Quite fast!

And now I have a blinking LED 😄, Next step is to port the 1 millisecond “systick” from HAL driver, and the milliseconds delay based on it.

The final code:

/*
* Blinking the LED on the Nucleo L152RE board using blocking delays.
*
* Copyright (C) 2017 Vasile Guta-Ciucur
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*/


#include "libopencm3/stm32/pwr.h"
#include "libopencm3/stm32/flash.h"
#include "libopencm3/stm32/rcc.h"
#include "libopencm3/stm32/gpio.h"

void set_nucleo_l152re_clock(void);
void my_delay_us(uint32_t us);


void set_nucleo_l152re_clock(void){
/* Turn on the appropriate source for the PLL */
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
/*
* Set prescalers for AHB, ADC, ABP1, ABP2.
* Do this before touching the PLL.
*/
rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);
rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV);
rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);

rcc_periph_clock_enable(RCC_PWR);
pwr_set_vos_scale(PWR_SCALE1);

pwr_disable_backup_domain_write_protect ();
rcc_osc_on(RCC_LSE);
rcc_wait_for_osc_ready(RCC_LSE);
rcc_rtc_select_clock(RCC_CSR_RTCSEL_LSE);
RCC_CSR |= RCC_CSR_RTCEN; /* Enable RTC clock */
pwr_enable_backup_domain_write_protect ();

flash_64bit_enable();
flash_prefetch_enable();
flash_set_ws(1);

rcc_set_pll_configuration(RCC_CFGR_PLLSRC_HSI_CLK, RCC_CFGR_PLLMUL_MUL6,
RCC_CFGR_PLLDIV_DIV3);

/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);

/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);

/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = 32000000;
rcc_apb1_frequency = 32000000;
rcc_apb2_frequency = 32000000;
}


void my_delay_us(uint32_t us) {
us *= 32;
us--; // ~ #46 on MSI
__asm__ volatile(" mov r0, %[us] \n\t"
"1: subs r0, #5 \n\t"
" bhi 1b \n\t"
:
: [us] "r" (us)
: "r0");
}

static void gpio_setup(void)
{
/* Enable GPIOA clock. */
rcc_periph_clock_enable(RCC_GPIOA);
/* Set GPIO5 (in GPIO port A) to 'output and no push-pull'. */
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO5);
}

int main(void)
{
int i;
set_nucleo_l152re_clock();
gpio_setup();
/* Blink the LED (PA5) on the board. */
while (1) {
gpio_toggle(GPIOA, GPIO5); /* LED on/off */
for (i = 0; i < 1000; i++){ /* ~1 second delay */
my_delay_us(1000);
}
}
return 0;
}

The linker script:

/* Specify the memory areas */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 80K
eep (r) : ORIGIN = 0x08080000, LENGTH = 16K
}

/* Include the common ld script. */
INCLUDE libopencm3_stm32l1.ld

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.