-
Notifications
You must be signed in to change notification settings - Fork 130
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
eRPC on stm32f7 #638
Comments
Yes, likely! I'm looking to replace our rather underdocumented and unmaintained XPCC protocol with something more standardized. eRPC looks very useful for that purpose, especially with a modm transport layer port! |
Well I can't really say that erpc is superior, but it's lightweight enough and there are a lot of people doing stuff with it currently.
The problem is, that as far as I can see, ERPC expects drivers for the transport layers to be included in the transport as well. I rather hate the idea of writing transport layers for:
My next step would be to implement a generic UserChannelTransport, which utilizes callbacks from the user code to allow whatever driver behavior or action with the incoming or outgoing data. Because we are planning to use ERPC and modm heavily in the future, I'll do some further development and will post possible use-cases/results here :) |
Yeah, modm is a little too low level in that regard, we have very different interfaces for each peripheral and even separate types per instance. I typically create a higher-level virtual interface that is then implemented via template class wrapper, but it's not the best solution. See |
well my idea was to just do something like this: class erpc::UserChannel{
// erpc transport api
isConnected(){}
readCallback(uint8_t* data, uint32_t size){
// implement whatever protocol you want
// and do whatever to read some data and fill the data* object
// could be CAN, UART, etc
}
write()
// implement whatever protocol you want
// and do whatever to write some data
// could be CAN, UART, etc
};
int main()
{
erpc::UserChannel A();
// init erpc and stuff ...
transport = erpc::UserChannelTransport_init(&A)
// do stuff to further initialize erpc things
} so it is probably similar enough to your suggestion (correct me if im wrong). Would you rather implement every protocol as a device wrapper and push that into erpc then? What is |
Yes, of course. I just wanted to give you context how we solved it in the past.
Ideally the eRPC repo would not be modified and instead you would store a modified copy in modm and copy that instead via lbuild. But I'm not sure exactly how much changes are required, perhaps a real fork of eRPC is required instead of a few patches.
The base class contains state continuations for running 2 coroutine functions in parallel without nesting. See https://modm.io/reference/module/modm-processing-resumable The alternative is |
That depends on what we would want to do. There are no changes necessary except for the "modm transport layer" but even that could be added to the original erpc via lbuild (and these changes are either part of modm or come from wherever). I'm gonna play around and see where this leads me :) |
@salkinium is there a working example of https://modm.io/reference/module/modm-processing-protothread/ ? And the UART example you gave does not contain a means to instantiate and "use" that thing either (at least i could not find one). So I have no idea what do do with it :) |
@rleh PT_WAIT_UNTIL(timeout.isExpired()); blocks indefinitely |
Are you running the unmodified example on a STM32F4 Discovery board? |
I just tested the code on an STM32F407 Discovery Board: Works perfectly! |
My LED example still blocks Edited: fixed errors #pragma once
#include <modm/board.hpp>
#include <modm/processing/protothread.hpp>
using Led1 = Board::LedGreen;
using Led2 = Board::LedBlue;
class BlinkingLight : public modm::pt::Protothread
{
public:
bool
run()
{
PT_BEGIN();
Led1::setOutput();
Led2::setOutput();
while (true){
timeout.restart(100ms);
Led1::toggle();
Led2::toggle();
PT_WAIT_UNTIL(timeout.isExpired());
MODM_LOG_ERROR<< "NEVER REACH" << modm::endl;
}
PT_END();
}
private:
modm::ShortTimeout timeout;
};
BlinkingLight light;
int main()
{
Board::initialize();
Board::LedRed::setOutput();
while(true){
light.run();
Board::LedRed::toggle();
modm::delay(200ms);
}
return 0;
}
|
Please provide more information for others to be able to reproduce the error, at least the target (dev board or MCU) your build setup and the I can't reproduce you example, even after adding the necessary includes
because some code is missing:
|
I created an example and tested it successfully on a Nucleo-F767ZI: 9554d61 |
I found the problem: |
I cant really find anything, any ideas on what could disrupt modm timers? |
Probably related to the SysTick timer (hardware) and modm|s system clock. Have you checked if the system clock still works? |
from https://docs.modm.io/develop/api/stm32l486zgt7/group__modm__architecture__clock.html while(true)
{
const auto start = modm::PreciseClock::now();
modm::delay(100ms);
const auto duration = modm::PreciseClock::now() - start;
MODM_LOG_DEBUG << "Function took " << duration << modm::endl;
} output:
|
compared to
when i do not add <modules>
<module>modm:erpc</module>
</modules> |
Does eRPC touch any SysTick registers? Perhaps it defines the |
It doesn't look like: https://github.com/kikass13/erpc/search?q=SysTick But maybe FreeRTOS (dependency of the erpc module) causes the trouble...? |
I can confirm: Adding the module |
yes, i had freertos as a module dependency in my erpc module.lb which probably caused these problems (in the sense that i included freertos accidentally as well) |
after removing the (useless) freertos dependency (i used freeRtos in my erpc example before and that worked with server + client) in from protothread example, the erpc server + led pthreads can run succesfully |
@salkinium @rleh is the use of protothreads even possible without writing intrusive code into erpc ? aka: is it possible to have a protothread and do a (wait for/yielding) loop somwhere internally without stealing the program control?
obviously that does not work, what happens is:
|
No. Resumable Functions and the C++20 coroutines are language solutions and therefore require all caller function signature to "upgrade" to the async syntax. You've stumbled across the main problem with this approach: Calling a async function from inside a sync function. The only solution is to convert your code to explicit polling, ie. periodically polling a sync function like We want to introduce stackful fibers into modm as an alternative, see #439. I need to find the time to finish it though… |
… all the code and cleaned it up a lot; Changed erpc transport layer to be the new ModmDeviceTransport, which is far superior in all ways modm-io/modm#638
…design; we use freertos threads for now because they make life easy; added erpc transport layer ModmDeviceTransport, which is far superior in all ways modm-io#638 because it is generic
UpdateThe stm32F7 example i am using (using freerots tasks) can be seen here (it was set to public by my orga): The modm fork containing the erpc module is here:
Other StuffThere is also a proper FreeRtos Thread wrapper class construct in the example (if someone is interested) :)
#include <modm/processing/rtos.hpp>
class TaskBase {
public:
TaskHandle_t handle_;
~TaskBase() {
vTaskDelete(handle_);
return;
}
};
class Task : public TaskBase {
public:
Task(char const*name, unsigned portBASE_TYPE priority, unsigned portSHORT stackDepth=configMINIMAL_STACK_SIZE) {
xTaskCreate(&taskfun, (const char*)name, stackDepth, this, priority, &handle_);
}
virtual void task() = 0;
static void taskfun(void* param) {
static_cast<Task *>(param)->task();
vTaskDelete(static_cast<Task *>(param)->handle_);
}
};
class ModmTask : public Task {
public:
ModmTask(char const*name, unsigned portBASE_TYPE priority, unsigned portSHORT stackDepth=configMINIMAL_STACK_SIZE)
: Task(name, priority, stackDepth){
MODM_LOG_INFO << "[System *] Task '" << name << "' created" << modm::endl;
updateStatus();
}
~ModmTask(){
MODM_LOG_INFO << "[System #] Task '" << status_.pcTaskName << "' removed" << modm::endl;
}
static void taskfun(void* param) {
static_cast<Task *>(param)->task();
vTaskDelete(static_cast<Task *>(param)->handle_);
}
public:
void sleep(TickType_t ticks){
vTaskDelay(ticks);
}
void updateStatus()
{
/* Use the handle to obtain further information about the task. */
vTaskGetInfo(
/* The handle of the task being queried. */
this->handle_,
/* The TaskStatus_t structure to complete with information on xTask. */
&this->status_,
/* Include the stack high water mark value in the
TaskStatus_t structure. */
pdTRUE,
/* Include the task state in the TaskStatus_t structure. */
eInvalid
);
}
public:
TaskStatus_t status_;
private:
}; and heres an example Task (blink led) using it #include <modm/board.hpp>
#include <utils/Task.hpp>
template <class Gpio, int SleepTime>
class LedTask : public ModmTask{
public:
LedTask() : ModmTask("LedTask", 6)
{}
void task()
{
Gpio::setOutput();
while (true)
{
sleep(SleepTime * MILLISECONDS);
Gpio::toggle();
{
static modm::rtos::Mutex lm;
modm::rtos::MutexGuard m(lm);
}
}
}
}; |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Hi,
i wanted to let you know that eRPC is working with modm. I have changed erpc slightly and created an example which utilizes local FIFOs (could be any other protocol) and freertos to do RPC's.
My plan for the future is to implement a transport layer for CAN, UART and Ethernet, all of them utilizing the driver stuff modm already provides.
First question:
Is this of some use to anyone?
The text was updated successfully, but these errors were encountered: