arduino-libraries / Arduino_MachineControl

GNU Lesser General Public License v2.1
38 stars 29 forks source link

Crash on digitalinput.init() #88

Closed JustusRijke closed 2 years ago

JustusRijke commented 2 years ago

The following sketch works on my Arduino Machine Control (blink digital output 0):

#include <Arduino_MachineControl.h>

using namespace machinecontrol;

bool state;

void setup() {
//  digital_inputs.init();
}

void loop() {
  digital_outputs.set(0, state);
  state=!state;
  delay(500);
}

However, when I uncomment // digital_inputs.init(); Portenta becomes unreachable (fixed by pressing reset button twice).

Can someone confirm this behavior?

Software used:

Board info:

Arduino loader
Magic Number (validation): a0
Bootloader version: 23
Clock source: External oscillator
USB Speed: USB 2.0/Hi-Speed (480 Mbps)
Has Ethernet: Yes
Has WiFi module: Yes
RAM size: 8MB
QSPI size: 16 MB
Has Video output: Yes
Has Crypto chip: Yes
JustusRijke commented 2 years ago

Fixed by adding #include "Wire.h" and Wire.begin();.

JustusRijke commented 2 years ago

However... when trying to run this on both cores (CM4 and CM7), with the code shown below, there seems to be interference. When activating input 1, output 1 flickers. I suppose this is because of the communication with the I/O expander happening from both cores simultaneously.

What is the proper way to access the I/O expander from both cores?

CM4:

#include <Arduino_MachineControl.h>
#include "Wire.h"

using namespace machinecontrol;

void setup()
{
  Wire.begin();
  digital_inputs.init();
}

void loop()
{
   digital_outputs.set(1, digital_inputs.read(DIN_READ_CH_PIN_01));
}

CM7:

#include <Arduino_MachineControl.h>
#include "Wire.h"

using namespace machinecontrol;

void setup()
{
  Wire.begin();
  digital_inputs.init();
  LL_RCC_ForceCM4Boot();
}

void loop()
{
   digital_outputs.set(0, digital_inputs.read(DIN_READ_CH_PIN_00));
}
facchinm commented 2 years ago

Hi @JustusRijke , if you need to perform operations on the same bus (in this case i2c) from both cores you need to manually implement a mutex-like RPC function (or a shared variable) to signal that the peripheral is being used. A possible snippet would be similar to

CM7

bool status = false;
bool getBusstatus() { return status; }
void setBusStatus(bool _status) { status = _status; }
RPC.bind("getStatus", getBusstatus);
RPC.bind("setStatus", setBusStatus);

...
// on i2c operation
if (status == false) {
  status = true;
  // do the operation
  status = false;
}

CM4

// on i2c operation
if (RPC.call("getStatus").as<bool>()) {
  RPC.call("setStatus", true);
  // do the real operation
  RPC.call("setStatus", false);
}
JustusRijke commented 2 years ago

Hi Martino, First of all: thanks for your support.

RPC seems quite slow. The test code below should toggle an output every 1 ms, but in reality this is 5 ms. So we used shared memory to communicate between cores, this works fine.

Original problem solved, closing the issue.

CM4:

#include <Arduino_MachineControl.h>
#include "Wire.h"
#include "RPC.h"

using namespace std::chrono_literals;
using namespace events;
using namespace machinecontrol;

EventQueue event_queue;

void task()
{
  digital_outputs.set(7, RPC.call("get_toggle").as<bool>()); // this takes approx. 5 ms
}

void setup()
{
  Wire.begin();
  RPC.begin();
  event_queue.call_every(1ms, &task);
  event_queue.dispatch_forever();
}

void loop()
{
}

CM7:

#include <Arduino_MachineControl.h>
#include "RPC.h"

bool toggle;

bool get_toggle()
{
  toggle = !toggle;
  return toggle;
}

void setup()
{
  RPC.begin();
  RPC.bind("get_toggle", get_toggle);
}

void loop()
{
}