Hi everyone,

We are using RIOT in a commercial project - LoRa modules based on Semtech
SX1276 transceiver and STM32L151CC MCU; previously, we had some experience
with Contiki and didn't like it at all. RIOT is much more attractive, but
unfortunately, there's only basic support for STM32L1: no low-power modes at
all, I2C driver hangs on any bus error including NACK, etc. Current RIOT
version doesn't even builds for STM32L1-based boards.

So we fixed it.

Here it is: https://github.com/unwireddevices/RIOT/tree/stm32l1_lpm

What has been fixed/improved:

1) Low-Power Modes (LPM). DEEPSLEEP with configurable core clock (default is
65 kHz MSI), STOP, STANDBY, switching to MSI clock, including LP-RUN mode.
GPIOs are automatically configured before entering sleep to minimize power
consumptions according to the rules:
    a) if SPI interface is enabled, switch SCK and MOSI to DO, 0; NSS to DO,
1
    b) if UART interface is enabled, switch TX to DO, 1
    c) disable USART controllers (otherwise we received some garbage on
L152RE - but not on L151CC - while playing with GPIOs)
    d) keep state of GPIOs configured for EXTI (external interrupts - you
may have some buttons etc. on them used to wake up MCU, so you don't want
them to be disabled during sleep)
    e) keep state of GPIOs configured with
lpm_arch_add_gpio_exclusion(gpio_t gpio) and
lpm_arch_del_gpio_exclusion(gpio_t gpio) functions (e.g. you have some
peripheral devices attached to GPIOs and don't want them to change their
state during sleep)
     f) switch all other GPIOs to AIN, no pull-up, no pull-down

After waking up, all GPIOs will be restored to their original state.

NB: there's CPU_NUMBER_OF_PORTS define, it should be set according to your
MCU. For example, L152RE has 8 ports (GPIOA...GPIOH) while L151CC only 6
ports (GPIOA...GPIOE, GPIOH). Although for some reason they didn't mention
it in datasheet nor RM0038, accessing GPIOF on L151CC will result in Bus
Fault (but if you want to get rid of CPU_NUMBER_OF_PORTS, you can always
catch HardFaults manually).

NB: to get the best power consumption possible, you have to set digital
inputs of external devices to 0 or 1 if they don't have pullups (e.g. I2C
have external pullups as a rule, but SPI doesn't). Otherwise, if you just
switch corresponding GPIO to AIN, input connected to it will be in some
state defined by random noises, probably switching between 0 and 1 and
consuming few dozens microamperes (e.g. if you just switch SPI off and
corresponding pins to AIN with SX1276 connected to it, it will consume about
100-200 uA instead of expected 1 uA).

NB: it is possible to switch between core frequencies by calling
lpm_set(LPM_IDLE) (switch to MSI) and lpm_set(LPM_RUN) (back to default
clock, usually HSE or HSI). Timer frequencies and STDIO UART baudrate will
be recalculated and preserved if possible (e.g. don't expect 460 kbps UART
with 32 kHz MSI clock), but other clocks have to be fixed manually.

2) ADC. Support for special channels - on-chip temperature (not very useful)
and reference voltage (extremely useful).

NB: reference voltage is NOT reported, instead Vdd is calculated. As a rule,
you don't need to know Vref, but you have to know Vdd to convert ADC
readings to volts.

3) I2C. Two major problems solved:

    a) inability to handle NACK. Default I2C driver _always_ waits for ACK,
so any problem on a bus will result in an endless loop. NACK is needed to
check if device is present on a bus, and some devices use NACK as part of
their regular protocol (SHT21, for example)
    b) inability to use 2 devices on a same I2C bus. Each device tries to
initialize the bus, and initializing already initialized I2C bus results in
BERR. Simplest solution is to leave initialization as it is, but turn off
I2C before it.

4) RTC timer can be used to wake up CPU from SLEEP/STOP/STANDBY.

5) Small fixes. Proper GPIO operations (with intermediary variable and
without intermediary glitches), CMSIS updated, BRR register enabled for
HD/XL devices only, etc.

NB: everything is provided AS IS. Code was mostly tested on our own boards
with our own RIOT build. It builds for BOARD=nucleo-l1, but only some
functions were actually tested on it.

--
Oleg Artamonov
+7 (916) 631-34-90
www.unwds.com


_______________________________________________
devel mailing list
devel@riot-os.org
https://lists.riot-os.org/mailman/listinfo/devel

Reply via email to