Skip to content

Commit

Permalink
[platform] Add support for STM32G0Bx/Cx devices
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Jun 7, 2023
2 parents 1f0251c + 76d2d49 commit 768d749
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 23 deletions.
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -82,9 +82,9 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git

## Microcontrollers

modm can create a HAL for <!--allcount-->3628<!--/allcount--> devices of these vendors:
modm can create a HAL for <!--allcount-->3715<!--/allcount--> devices of these vendors:

- STMicroelectronics STM32: <!--stmcount-->2823<!--/stmcount--> devices.
- STMicroelectronics STM32: <!--stmcount-->2910<!--/stmcount--> devices.
- Microchip SAM: <!--samcount-->416<!--/samcount--> devices.
- Microchip AVR: <!--avrcount-->388<!--/avrcount--> devices.
- Raspberry Pi: <!--rpicount-->1<!--/rpicount--> device.
Expand Down Expand Up @@ -164,7 +164,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">✅</td>
<td align="center">○</td>
<td align="center">✕</td>
Expand Down
5 changes: 5 additions & 0 deletions src/modm/platform/can/stm32-fdcan/module.lb
Expand Up @@ -64,6 +64,11 @@ def prepare(module, options):
if not device.has_driver("fdcan:stm32"):
return False

# STM32G0 devices are currently unsupported due to shared interrupt handler
# TODO: fix driver
if device.identifier.family == "g0":
return False

module.depends(
":architecture:assert",
":architecture:atomic",
Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/core/stm32/startup_platform.c.in
Expand Up @@ -63,7 +63,7 @@ __modm_initialize_platform(void)
%% elif target.family in ["g0", "g4", "l4", "l5"]
%% if target.family in ["l4", "g4"]
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
%% else
%% elif target.family != "g0"
#ifdef PWR_CR2_IOSV
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
#endif
Expand Down
6 changes: 3 additions & 3 deletions src/modm/platform/dma/stm32/module.lb
Expand Up @@ -5,7 +5,7 @@
# Copyright (c) 2017, Fabian Greif
# Copyright (c) 2020, Mike Wolfram
# Copyright (c) 2021, Raphael Lehmann
# Copyright (c) 2021, Christopher Durand
# Copyright (c) 2021-2023, Christopher Durand
#
# This file is part of the modm project.
#
Expand Down Expand Up @@ -129,11 +129,11 @@ def build(env):
for channel in channels:
instance_channels[channel["dma-instance"]].append(channel["dma-channel"])
for instance in instance_channels:
channel_list = instance_channels[instance]
channel_list = [int(c) for c in instance_channels[instance]]
channel_list.sort()
min_channel = channel_list[0]
max_channel = channel_list[-1]
controller.append({"instance": int(instance), "min_channel": int(min_channel), "max_channel": int(max_channel)})
controller.append({"instance": int(instance), "min_channel": min_channel, "max_channel": max_channel})
elif dma["type"] in ["stm32-stream-channel"]:
for channels in dma["streams"]:
max_channels = 0
Expand Down
32 changes: 26 additions & 6 deletions src/modm/platform/i2c/stm32-extended/i2c_master.cpp.in
Expand Up @@ -2,6 +2,7 @@
/*
* Copyright (c) 2017, Niklas Hauser
* Copyright (c) 2017, Sascha Schade
* Copyright (c) 2018, 2023, Christopher Durand
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -53,7 +54,7 @@
#include <modm/container.hpp>
#include <modm/platform/clock/rcc.hpp>

%% if not shared_interrupt
%% if not single_interrupt
MODM_ISR_DECL(I2C{{ id }}_ER);
%% endif

Expand Down Expand Up @@ -323,20 +324,35 @@ namespace
}

// ----------------------------------------------------------------------------
%% if shared_interrupt
%% if shared_irq
void
modm::platform::I2cMaster{{ id }}::irq()
%% elif single_interrupt
MODM_ISR(I2C{{ id }})
%% else
MODM_ISR(I2C{{ id }}_EV)
%% endif
{
DEBUG_STREAM("\n=== IRQ ===");

%% if shared_interrupt
%% if single_interrupt
handleError();
%% endif

uint16_t isr = I2C{{ id }}->ISR;
const uint16_t isr = I2C{{ id }}->ISR;
%% if shared_irq
const auto cr1 = I2C{{ id }}->CR1;
const auto mask = (cr1 & (I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE))
| ((cr1 & I2C_CR1_TCIE) ? (I2C_ISR_TCR | I2C_ISR_TC) : 0u);

static_assert(I2C_CR1_STOPIE == I2C_ISR_STOPF);
static_assert(I2C_CR1_TXIE == I2C_ISR_TXIS);
static_assert(I2C_CR1_RXIE == I2C_ISR_RXNE);

if ((isr & mask) == 0) {
return;
}
%% endif
I2C{{ id }}->CR1 &= ~(I2C_CR1_STOPIE | I2C_CR1_TCIE | I2C_CR1_RXIE | I2C_CR1_TXIE);

I2C{{ id }}->ICR = I2C_ICR_STOPCF;
Expand Down Expand Up @@ -487,7 +503,7 @@ MODM_ISR(I2C{{ id }}_EV)
}

// ----------------------------------------------------------------------------
%% if not shared_interrupt
%% if not single_interrupt
MODM_ISR(I2C{{ id }}_ER)
{
handleError();
Expand Down Expand Up @@ -539,7 +555,11 @@ modm::platform::I2cMaster{{ id }}::initializeWithPrescaler(uint32_t timingRegist
// Disable Own Address 2
I2C{{ id }}->OAR2 = 0;

%% if shared_interrupt
%% if shared_irq
// Enable Interrupt
NVIC_SetPriority({{ shared_irq }}_IRQn, 10);
NVIC_EnableIRQ({{ shared_irq }}_IRQn);
%% elif single_interrupt
// Enable Interrupt
NVIC_SetPriority(I2C{{ id }}_IRQn, 10);
NVIC_EnableIRQ(I2C{{ id }}_IRQn);
Expand Down
9 changes: 9 additions & 0 deletions src/modm/platform/i2c/stm32-extended/i2c_master.hpp.in
Expand Up @@ -2,6 +2,7 @@
/*
* Copyright (c) 2017, Sascha Schade
* Copyright (c) 2017-2018, Niklas Hauser
* Copyright (c) 2018, 2023, Christopher Durand
*
* This file is part of the modm project.
*
Expand All @@ -14,6 +15,7 @@
#ifndef MODM_STM32_I2C_{{ id }}_HPP
#define MODM_STM32_I2C_{{ id }}_HPP

#include <modm/architecture/interface/interrupt.hpp>
#include <modm/architecture/interface/i2c_master.hpp>
#include <modm/architecture/interface/clock.hpp>
#include <modm/platform/gpio/connector.hpp>
Expand Down Expand Up @@ -117,6 +119,13 @@ public:
private:
static void
initializeWithPrescaler(uint32_t timingRegisterValue);

%% if shared_irq
friend void ::{{ shared_irq }}_IRQHandler();

static void
irq();
%% endif
};


Expand Down
25 changes: 25 additions & 0 deletions src/modm/platform/i2c/stm32-extended/i2c_shared_irqs.cpp.in
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2023, Christopher Durand
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

%% for ids in shared_irqs.values()
%% for id in ids | sort
#include "i2c_master_{{ id }}.hpp"
%% endfor
%% endfor

%% for irq,ids in shared_irqs.items()
MODM_ISR({{ irq }})
{
%% for id in ids | sort
modm::platform::I2cMaster{{ id }}::irq();
%% endfor
}
%% endfor
35 changes: 33 additions & 2 deletions src/modm/platform/i2c/stm32-extended/module.lb
Expand Up @@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2016-2018, Niklas Hauser
# Copyright (c) 2017, Fabian Greif
# Copyright (c) 2023, Christopher Durand
#
# This file is part of the modm project.
#
Expand All @@ -10,6 +11,23 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------

from collections import defaultdict
import re

global_properties = {}

def get_shared_irqs(device):
irq_re = re.compile("I2C\d(_\d)+")
shared_irqs = [v["name"] for v in device.get_driver("core")["vector"]]
shared_irqs = [v for v in shared_irqs if irq_re.fullmatch(v)]
shared_irq_map = {}
for irq in shared_irqs:
instances = tuple(irq[3:].split("_"))
for i in instances:
shared_irq_map[int(i)] = irq
return shared_irq_map


class Instance(Module):
def __init__(self, instance):
self.instance = instance
Expand All @@ -31,13 +49,21 @@ class Instance(Module):
return True

def build(self, env):
global global_properties

device = env[":target"]
driver = device.get_driver("i2c")

properties = device.properties
properties["target"] = target = device.identifier
properties["id"] = self.instance
properties["shared_interrupt"] = "0" in target.family
properties["single_interrupt"] = "0" in target.family
shared_irq = get_shared_irqs(device).get(self.instance)
properties["shared_irq"] = shared_irq
if shared_irq:
global_properties["shared_irqs"][shared_irq].append(self.instance)
# shared irq is only supported with a single data and error interrupt
assert properties["single_interrupt"] or not shared_irq

env.substitutions = properties
env.outbasepath = "modm/src/modm/platform/i2c"
Expand All @@ -64,12 +90,17 @@ def prepare(module, options):
":container",
":platform:gpio")

global_properties["shared_irqs"] = defaultdict(list)

for instance in listify(device.get_driver("i2c")["instance"]):
module.add_submodule(Instance(int(instance)))

return True

def build(env):
env.substitutions.update(global_properties)
env.outbasepath = "modm/src/modm/platform/i2c"
env.copy("i2c_timing_calculator.hpp")

env.copy("i2c_timing_calculator.hpp")
if len(global_properties["shared_irqs"]) > 0:
env.template("i2c_shared_irqs.cpp.in")
8 changes: 8 additions & 0 deletions src/modm/platform/spi/stm32/module.lb
Expand Up @@ -3,6 +3,7 @@
#
# Copyright (c) 2016-2018, Niklas Hauser
# Copyright (c) 2017, Fabian Greif
# Copyright (c) 2023, Christopher Durand
#
# This file is part of the modm project.
#
Expand Down Expand Up @@ -37,6 +38,13 @@ class Instance(Module):
properties = get_properties(env)
properties["id"] = self.instance

device = env[":target"]

irqs = [v["name"] for v in device.get_driver("core")["vector"]]
irqs = [irq for irq in irqs if irq.startswith("SPI") and str(self.instance) in irq]
assert len(irqs) == 1
properties["irq"] = irqs[0]

env.substitutions = properties
env.outbasepath = "modm/src/modm/platform/spi"

Expand Down
6 changes: 3 additions & 3 deletions src/modm/platform/spi/stm32/spi_hal_impl.hpp.in
Expand Up @@ -153,12 +153,12 @@ modm::platform::SpiHal{{ id }}::enableInterruptVector(bool enable, uint32_t prio
{
if (enable) {
// Set priority for the interrupt vector
NVIC_SetPriority(SPI{{ id }}_IRQn, priority);
NVIC_SetPriority({{ irq }}_IRQn, priority);
// register IRQ at the NVIC
NVIC_EnableIRQ(SPI{{ id }}_IRQn);
NVIC_EnableIRQ({{ irq }}_IRQn);
}
else {
NVIC_DisableIRQ(SPI{{ id }}_IRQn);
NVIC_DisableIRQ({{ irq }}_IRQn);
}
}

Expand Down
4 changes: 0 additions & 4 deletions test/all/ignored.txt
Expand Up @@ -106,10 +106,6 @@ samd21e15c-uf
samd21e15c-uu
samd21e16c-uf
samd21e16c-uu
# FIXME: Shared IRQs on UART, SPI, I2C
stm32g0b0
stm32g0b1
stm32g0c1
# FIXME: Dual-core devices not supported yet
stm32h745
stm32h755
Expand Down

0 comments on commit 768d749

Please sign in to comment.