-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[driver] Add GpioSampler for IO analysis
- Loading branch information
Showing
7 changed files
with
434 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* Copyright (c) 2018, Niklas Hauser | ||
* | ||
* 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/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#include "gpio_sampler.hpp" | ||
#include <modm/architecture/interface/interrupt.hpp> | ||
#include <modm/platform.hpp> | ||
#include <modm/debug/logger.hpp> | ||
|
||
using IrqHandler = void(*)(); | ||
%% if vectors_location == "rom" | ||
modm_fastdata | ||
IrqHandler exti_vectors[{{ extis | length }}] = {nullptr}; | ||
|
||
%% for vector in extis | ||
MODM_ISR({{ vector }}) | ||
{ | ||
exti_vectors[{{ loop.index0 }}](); | ||
} | ||
%% endfor | ||
%% endif | ||
|
||
const IRQn_Type | ||
irq_map[{{ extis | length }}] = | ||
{ | ||
%% for vector in extis | ||
{{ vector }}_IRQn, | ||
%% endfor | ||
}; | ||
|
||
namespace modm | ||
{ | ||
|
||
modm_fastdata | ||
void *GpioSampler::context{nullptr}; | ||
|
||
void | ||
GpioSampler::reset(Interrupt vector) | ||
{ | ||
const size_t index = int(vector); | ||
NVIC_DisableIRQ(irq_map[index]); | ||
NVIC_SetPriority(irq_map[index], 0); | ||
} | ||
|
||
void | ||
GpioSampler::setHandler(Interrupt vector, IrqHandler handler) | ||
{ | ||
const size_t index = int(vector); | ||
if (index >= {{ extis | length }}) return; | ||
%% if vectors_location == "ram" | ||
NVIC_SetVector(irq_map[index], (uint32_t) handler); | ||
%% else | ||
exti_vectors[index] = handler; | ||
%% endif | ||
NVIC_EnableIRQ(irq_map[index]); | ||
} | ||
|
||
GpioSampler::Channel::Channel() | ||
{} | ||
void | ||
GpioSampler::Channel::allocate(size_t max_samples) | ||
{ | ||
max_count = max_samples + 1; | ||
data = new Type[max_samples + 1]; | ||
} | ||
GpioSampler::Channel::~Channel() | ||
{ | ||
delete[] data; | ||
} | ||
|
||
void | ||
GpioSampler::Channel::reset() | ||
{ | ||
count = 0; | ||
} | ||
|
||
void | ||
GpioSampler::Channel::dump() const | ||
{ | ||
for (size_t ii=0; ii<count; ii++) { | ||
Type d = diff(ii); | ||
MODM_LOG_DEBUG.printf("%3u %9ld %6ld (%ldus)\n", ii, (*this)[ii], d, int32_t(int64_t(d * 1000000) / modm::platform::fcpu)); | ||
} | ||
MODM_LOG_DEBUG << modm::endl; | ||
} | ||
|
||
void | ||
GpioSampler::Channel::add(Type time) | ||
{ | ||
if (count < max_count) data[count++] = time; | ||
} | ||
|
||
const GpioSampler::Type& | ||
GpioSampler::Channel::operator[](size_t index) const | ||
{ | ||
return data[(index < count) ? index : (count - 1)]; | ||
} | ||
|
||
bool | ||
GpioSampler::Channel::read(size_t index) const | ||
{ | ||
return ((*this)[index] > 0); | ||
} | ||
|
||
GpioSampler::Type | ||
GpioSampler::Channel::diff(size_t index) const | ||
{ | ||
if (index == 0) return 0; | ||
Type s0 = (*this)[index - 1]; | ||
Type s1 = (*this)[index]; | ||
// abs | ||
uint32_t t0 = (s0 > 0) ? s0 : -s0; | ||
uint32_t t1 = (s1 > 0) ? s1 : -s1; | ||
// Fix overflow issues | ||
if (t1 < t0) t1 |= (1ul << 31); | ||
return t1 - t0; | ||
} | ||
|
||
} // namespace modm::platform |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
* Copyright (c) 2018, Niklas Hauser | ||
* | ||
* 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/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#ifndef MODM_TEST_LOGIC_ANALYZER_SAMPLER_HPP | ||
#define MODM_TEST_LOGIC_ANALYZER_SAMPLER_HPP | ||
|
||
#include <stdint.h> | ||
#include <stddef.h> | ||
#include <modm/platform/device.hpp> | ||
|
||
namespace modm | ||
{ | ||
|
||
class GpioSampler | ||
{ | ||
public: | ||
using Type = int32_t; | ||
|
||
class Channel | ||
{ | ||
friend class GpioSampler; | ||
size_t max_count = 0; | ||
volatile size_t count = 0; | ||
Type *data = nullptr; | ||
Channel(); | ||
void allocate(size_t max_samples); | ||
void add(Type time); | ||
void reset(); | ||
|
||
public: | ||
~Channel(); | ||
|
||
inline size_t max() const { return max_count; } | ||
inline size_t size() const { return count; } | ||
|
||
void dump() const; | ||
|
||
Type diff(size_t index) const; | ||
bool read(size_t index) const; | ||
|
||
const Type& operator[](size_t index) const; | ||
|
||
inline const Type* begin() const { return data; } | ||
inline const Type* end() const { return &data[count]; } | ||
}; | ||
|
||
template<size_t channels> | ||
class Handle | ||
{ | ||
friend class GpioSampler; | ||
using CleanupHandler = void(*)(); | ||
using StartHandler = void(*)(Handle<channels> &); | ||
|
||
const CleanupHandler cleanup; | ||
const StartHandler start; | ||
Channel data[channels]; | ||
|
||
Handle(size_t max_samples, StartHandler start, CleanupHandler cleanup); | ||
void set_start_time(const Type *start); | ||
public: | ||
static constexpr size_t Channels = channels; | ||
|
||
public: | ||
~Handle(); | ||
|
||
void | ||
restart(); | ||
|
||
const Channel& | ||
operator[](size_t channel) const; | ||
}; | ||
|
||
template< class... Gpios > | ||
static auto Create(size_t max_samples); | ||
|
||
protected: | ||
static void *context; | ||
|
||
enum class | ||
Interrupt : uint8_t | ||
{ | ||
%% for vector in extis | ||
{{ vector | capitalize }} = {{ loop.index0 }}, | ||
%% endfor | ||
}; | ||
|
||
template< size_t channels, size_t pin_count, uint8_t pin, class Gpio, class... Gpios > | ||
static void sampleGpio(Channel *data, Type time); | ||
template< size_t channels, size_t pin_count, uint8_t pin > | ||
static void sampleGpio(Channel *, Type) {} | ||
|
||
static void reset(Interrupt vector); | ||
static void setHandler(Interrupt vector, void(*handler)()); | ||
static inline Type getTime() { | ||
return Type(DWT->CYCCNT & ~(1ul << 31)); | ||
} | ||
}; | ||
|
||
} // namespace modm | ||
|
||
#include "gpio_sampler_impl.hpp" | ||
|
||
#endif // MODM_TEST_LOGIC_ANALYZER_SAMPLER_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (c) 2018, Niklas Hauser | ||
# | ||
# 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/. | ||
|
||
from collections import OrderedDict | ||
|
||
def init(module): | ||
module.parent = ":driver" | ||
module.name = "gpio_sampler" | ||
|
||
|
||
def prepare(module, options): | ||
if options[":target"].identifier["platform"] != "stm32": | ||
return False | ||
|
||
core = options[":target"].get_driver("core:cortex-m*") | ||
# Cortex-M0 doesn't have the DWT->CYCCNT and Cortex-M7 support is broken | ||
if not core or "m0" in core["type"] or "m7" in core["type"]: | ||
return False | ||
|
||
module.depends( | ||
":platform:gpio", | ||
":platform:core", | ||
":architecture:interrupt") | ||
return True | ||
|
||
|
||
def build(env): | ||
exti_vectors = [v["name"] for v in env[":target"].get_driver("core")["vector"] if "EXTI" in v["name"]] | ||
# These are all exti possible vectors: 0, 0_1, 1, 15_10, 2, 2_3, 2_TSC, 3, 4, 4_15, 9_5 | ||
extimap = { | ||
"0": [0], "1": [1], "2": [2], "3": [3], "4": [4], | ||
"0_1": [0,1], | ||
"2_TSC": [2], | ||
"2_3": [2,3], | ||
"4_15": [4,5,6,7,8,9,10,11,12,13,14,15], | ||
"9_5": [5,6,7,8,9], | ||
"15_10": [10,11,12,13,14,15], | ||
} | ||
extis = OrderedDict() | ||
for v in sorted(exti_vectors): | ||
extis[v] = extimap[v[4:]] | ||
|
||
env.substitutions = { | ||
"extis": extis, | ||
"vectors_location": env.get(":platform:core:vector_table_location", "rom") | ||
} | ||
env.outbasepath = "modm/src/modm/driver" | ||
env.template("gpio_sampler.cpp.in") | ||
env.template("gpio_sampler.hpp.in") | ||
env.template("gpio_sampler_impl.hpp.in") |
Oops, something went wrong.