Closed ralphBellofattoSTX closed 4 years ago
Starting with temporary wiring of the photon i2c device (differs from the board being layed out).
A simple programming change can move these pins when we get boards and are able to populate them.
first cut will be to connect the rpi to the device and run the i2cdetect program on the pi and get the bit banger on the ph0ton to ack it.
started on the class definitions and getting clean compile out of the photon workbench.
NOTE: I was not able to get the debugger to work. I suspect that this requires an external Jtag debug device which would better work on the photon Argon.
note to self, for more complex programs, develop on the argon then switch for production.
I2c state machine to reference
note to self, using ssstream (ostringstream) objects to deal with debug io, causes the the flash to overflow....
so.... drags in too much gorp... need another strategy for doing debug with high speed gorpage...
Need to define my own class to handle the debug print...
This also means a basic debug io technique i frequently use for debug io is not compatable with the small mem footprint.
had a setback.
Downloading to address = 0x080a0000, size = 462792
_dfu-util: Last page at 0x08110fc7 is not writeable
make[2]: *** [program-dfu] Error 74
Even after factor reset and reboot of host machine.
so photon not programmable any more.
Prior to this malfunction, was seeing issues with being able to even see 100khz i2c pulses on the photon.
It was not even seeing the i2c clock transitions.
So, we may need to slow down the clock.
Found this little bit of advice for doing that. https://www.raspberrypi-spy.co.uk/2018/02/change-raspberry-pi-i2c-bus-speed/
got some trace info on how frequently we can listen for io in a polling loop. wrote this minimal loop:
void loop() {
// turn on "led" pin (built-in blue LED light)
digitalWrite(led, HIGH);
digitalWrite(led, LOW);
return;
and we see:
and:
so with a digital write we can do ~3.3us
and when we exit "loop" and then return, a full 1ms has passed by...
also if we try to NOT exit loop, then we are no longer able to program the device.
so,,, this is going to be tricker than we thought.
so, bottom line, is a bitbanger i2c slave is not going to work unless we can get called in loop faster.. a lot faster...
interrupts:
PhotonNot supported on the Photon (you can't use attachInterrupt on these pins):
D0, A5 (shared with SETUP button)
No restrictions on the Photon (all of these can be used at the same time):
D5, D6, D7, A2, WKP, TX, RX
Shared on the Photon (only one pin for each bullet item can be used at the same time):
D1, A4
D2, A0, A3
D3, DAC
D4, A1
So, we need to be selective with the interrupt io...
and possibly what we attach to it....
need to make a test bench where we hm... demonstrate interrupts with something.
there is also this little note:
NOTE: pinMode() MUST be called prior to calling attachInterrupt() to set the desired mode for the interrupt pin (INPUT, INPUT_PULLUP or INPUT_PULLDOWN).
but one of the things we need to see is falling and rising SDA with SCL high, for start and stop. and we also need to change directions on the SDA pin.
with digital write fast we get a much shorter time between writes. (40ns)....
we might be able to combine the digtalFastWrite with an interrupt strategy, this may mean we have to select different pins....
some obvious questions,
What happens when we have an attached interrupt and then reverse the direction the an io pin. Do we have to cancel the interrupt.
What is the timing overhead of the set interrupt....? is it feasible to enable the SDA interrupt on the rising edge of SCL and disable it on the falling edge?
Going to have to get more timing info before we can have confidence in a design.
this suggests the following measurements.
enable interrupt on one pin and has a loop that toggles another pin to drive it, Measure the delay involved.
attach interrupt latency
interrupt callback latency
test to see how fast we can toggle the io pins and still field the interrupts.
measure the delay between the two waves..
here is the i2c timing we need to catch.
BTW, I’m pretty sure the debugger works on the VS Code-based version of the Particle IDE.
On Fri, Jun 5, 2020 at 5:56 PM ralph bellofatto notifications@github.com wrote:
started on the class definitions and getting clean compile out of the photon workbench.
NOTE: I was not able to get the debugger to work. I suspect that this requires an external Jtag debug device which would better work on the photon Argon.
note to self, for more complex programs, develop on the argon then switch for production.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/GlobalVent/wiki/issues/138#issuecomment-639844872, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAOIMWXDJQ4MKJJ5GRRN23RVFSZHANCNFSM4NR26O7Q .
@alcohen yes, that is where i ran into the debugger capabilities. It is looking for some USB debugging device and I suspect a jtag connection for the photon, which will take over 5 of of the digital IO pins. So, i'll experiment with the argon.
however, a more immediate issue here is what i discovered above, the time interval in the "loop" is 1ms from loop to loop, so we can't really poll i2c in there. so this will need to be some sort of interrupt based setup, and there are limits on the io pins, so if we did not pick 4 i2c pins that can have an independent interrupt on them, then it is time to take out the Xacto knife and wire wrap wire to reroute a couple of pins.
Polling for 100Khz signals is just not going to work.
Ah, sorry, I meant debugging over the USB.
Do you think the slow speeds are a function of the RTOS?
On Thu, Jun 11, 2020 at 7:55 PM ralph bellofatto notifications@github.com wrote:
@alcohen https://github.com/alcohen yes, that is where i ran into the debugger capabilities. It is looking for some USB debugging device and I suspect a jtag connection for the photon, which will take over 5 of of the digital IO pins. So, i'll experiment with the argon.
however, a more immediate issue here is what i discovered above, the time interval in the "loop" is 1ms from loop to loop, so we can't really poll i2c in there. so this will need to be some sort of interrupt based setup, and there are limits on the io pins, so if we did not pick 4 i2c pins that can have an independent interrupt on them, then it is time to take out the Xacto knife and wire wrap wire to reroute a couple of pins.
Polling for 100Khz signals is just not going to work.
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/GlobalVent/wiki/issues/138#issuecomment-642987366, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAOIMSYRRXTPDO6AKODVN3RWFVH5ANCNFSM4NR26O7Q .
debugging over usb seems to require an openocd compatible device, which the vscode plugin can't find with just the photon attached.
As far as the speeds, yes i believe it is due to the RTOS, two issues.
This causes the program to completely miss the i2c events unless they are really-really slow.
So, either I need to see if either
some other options are (manual mode). https://docs.particle.io/reference/device-os/firmware/photon/#manual-mode
and system thread: https://docs.particle.io/reference/device-os/firmware/photon/#system-thread
So, lets see how those work before I try to rework the entire control loop.
with system mode and persistence turned on.
SYSTEM_MODE(MANUAL);
int led = D6;
// SETUP function runs one time at start when device is powered on
void setup() {
// set "led" pin to be an output
pinMode(led, OUTPUT);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
// turn on "led" pin (built-in blue LED light)
digitalWriteFast(led, HIGH);
digitalWriteFast(led, LOW);
}
quite a bit of jitter. between 1-8us and variable... seems 8us is the max...
system thread enabled: ( in both these cases, the occasional long pulse is interesting..
SYSTEM_THREAD(ENABLED);
int led = D6;
// SETUP function runs one time at start when device is powered on
void setup() {
// set "led" pin to be an output
pinMode(led, OUTPUT);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
// turn on "led" pin (built-in blue LED light)
digitalWriteFast(led, HIGH);
digitalWriteFast(led, LOW);
}
To do an i2c slave at 100khz we need to detect and edge and respond within 5us, so even this mode is no viable unless we slow down the I2c bus from the rpi.
Which is doable for testing....
Both system thread and manual mode. The ocasional pulse that is 5us long is interesting.
That implies that sometimes that something happens to streach the pulse. Either an interrupt or something else.
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int led = D6;
// SETUP function runs one time at start when device is powered on
void setup() {
// set "led" pin to be an output
pinMode(led, OUTPUT);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
// turn on "led" pin (built-in blue LED light)
digitalWriteFast(led, HIGH);
digitalWriteFast(led, LOW);
}
single thread block... streached hi pulse is still a problem... https://docs.particle.io/reference/device-os/firmware/photon/#system-thread
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int led = D6;
// SETUP function runs one time at start when device is powered on
void setup() {
// set "led" pin to be an output
pinMode(led, OUTPUT);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
SINGLE_THREADED_BLOCK() {
// code here is executed atomically, without task switching
// or interrupts
digitalWriteFast(led, HIGH);
digitalWriteFast(led, LOW);
}
}
trying ATOMIC_BLOCK -- the extended pulse goes away....
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int led = D6;
// SETUP function runs one time at start when device is powered on
void setup() {
// set "led" pin to be an output
pinMode(led, OUTPUT);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
ATOMIC_BLOCK() {
// code here is executed atomically, without task switching
// or interrupts
digitalWriteFast(led, HIGH);
digitalWriteFast(led, LOW);
}
}
next, interrupt latency, how fast can we do an interrupt and then turn around a reply within an atomic block.
This suggests an interrupt based approach, rather than polling in the device..
interrupt latency test: (quite a bit of jitter), the nominal 2us is ok, but sometimes it is quite a bit longer... which would cause the i2c slave to miss samples.
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int IOUT = D6;
int IIN = D5;
int TOUT = A0;
// SETUP function runs one time at start when device is powered on
unsigned cnt = 0;
void pinChangeInt() {
digitalWriteFast(TOUT, cnt);
}
void setup() {
// set "led" pin to be an output
pinMode(TOUT, OUTPUT);
pinMode(IOUT, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
attachInterrupt(IIN, pinChangeInt, CHANGE);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
ATOMIC_BLOCK() {
// code here is executed atomically, without task switching
// or interrupts
cnt++;
digitalWriteFast(IOUT, cnt);
}
delay(1);
}
can we play with interrupt priorities? (yes). and it improves the latency...
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
So, now to come up with a design that will work based on interrupts.
Next proof of concept, is can we trigger an interrupt, on the falling edge of SDA (start) and then disconnect the interrupt and process the i2c transaction while polling in the interrupt handler.
And then reenable the stop event or a timeout of 9*4 bit times.
Do time functions work in the interrupt handler?
Thanks for the interrupt summary, was very useful. Only one conflict luckily, will be bridging A0 to A4 to allow RPi_SDA to get an interrupt: also checking in a new version of the simulator schematic to GitHub which shows the rework.
doing proof of concept to see if we can handle the entire cycle within an interrupt routine.
To detect the start and stop we have to interrupt on the SDA pin which also requires us to reverse direction while we are handling the interrupt.
// SETUP function runs one time at start when device is powered on
unsigned cnt = 0;
void pinChangeInt() {
unsigned d;
d=pinReadFast(IIN);
pinMode(IIN,OUTPUT);
pinMode(IIN,INPUT_PULLUP);
digitalWriteFast(TOUT, d);
}
void setup() {
// set "led" pin to be an output
pinMode(TOUT, OUTPUT);
pinMode(IOUT, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
ATOMIC_BLOCK() {
// code here is executed atomically, without task switching
// or interrupts
cnt++;
digitalWriteFast(IOUT, cnt);
}
delay(1);
}
causes the device to become un-programmable without a physical reset
_dfu-util: No DFU capable USB device available
make[2]: *** [program-dfu] Error 74
make[1]: *** [modules/photon/user-part] Error 2
make: *** [flash-user] Error 2
The terminal process terminated with exit code: 2
so
we need to detect the start and stop conditions.
https://user-images.githubusercontent.com/38866041/84447669-a4a8b800-ac16-11ea-8f7c-e5f0da4f3691.png
testing this sequence, can we disable the interrupt during the cycle and then re-enable it when reversing the SDA output:
This blows our time budget of 3us..
digitalWriteFast(TOUT, 1);
#if 1
detachInterrupt(IIN);
d=pinReadFast(IIN);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
#endif
digitalWriteFast(TOUT, 0);
this test, doing the detatch in the interrupt routine and then re-arm.
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int IOUT = D6;
int IIN = D5;
int TOUT = A0;
// SETUP function runs one time at start when device is powered on
unsigned cnt = 0;
void pinChangeInt() {
unsigned d;
digitalWriteFast(TOUT, 1);
detachInterrupt(IIN);
d=pinReadFast(IIN);
digitalWriteFast(TOUT, 0);
}
void setup() {
// set "led" pin to be an output
pinMode(TOUT, OUTPUT);
pinMode(IOUT, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
ATOMIC_BLOCK() {
// code here is executed atomically, without task switching
// or interrupts
cnt++;
digitalWriteFast(IOUT, cnt);
}
delay(1);
}
That leaves us with 1us left to do all our processing...
we can re-arm once we see the stop transaction, and hope we get around to re-arm at the end,
there is a possibility we may miss 2 back to back i2c transactions...
cost of a SCL line reversal: 11us, yikes, that is way over the 3-5us budget we have.
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int IOUT = D6;
int IIN = D5;
// SETUP function runs one time at start when device is powered on
void setup() {
// set "led" pin to be an output
pinMode(IOUT, OUTPUT);
}
// LOOP function runs in repeating loop (after setup finishes)
void loop() {
ATOMIC_BLOCK() {
digitalWriteFast(IOUT, 1);
pinMode(IIN, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
digitalWriteFast(IOUT, 0);
}
delay(1);
}
If it’s of any interest... yesterday I started playing with an $11 Nucleo board from ST which features ths chip. Easy to develop on using VisualGDB, debugging works through the USB. One nice thing is that it has two i2c ports that can be slaves. I’m programming using C on mbed framework from ARM, so it does have an OS, but having “real” i2c might be nice. If this is of possible interest I can do some measurements.
@alcohen interesting, can the slaves be programmed to respond to multiple i2c addresses and how does one interface to it to support different "commands" to a given i2c device?
Can you point to a link for the documentation on how to use the i2c devices as a slave, and in our use case multiple slaves?
the timing measurements done so far indicate that we are definitely going to have to slow down the i2c clock.
It supposedly is possible to slow down the i2c clock with a boot time parameter. https://www.raspberrypi-spy.co.uk/2018/02/change-raspberry-pi-i2c-bus-speed/
this example only shows speeding up the clock to 400Mhz, we need to slow it down to 20 mhz. so a simple proof of concept is in order.
with a line turnaround time of 11us, we need a 1/2 clock time of that time plus some time to actually do some calculation, so that leaves us with at least 12us or a 24us clock... or a i2c baud rate of 50Mhz. so 20Mhz should more than cover it. we can try to tighten it up later.
so at 20Mhz, we get a duty cycle of 50us and a 1/2 clock cycle of 25us..
The entire cycle of handling the i2c is going to have to be done inside an interrupt handler, which won't return until either the stop condition, or a timeout.
Our longest read data is a command device address + 3 data bytes (to read the adc)... so that is start+(93)+stop (so 29 bits). This means we are holding off interrupts for 2950us, 1.45ms.
hopefully that does not cause problems with the RTOS on the photon...
That should get us started. setting the boot parameter as follows:
dtparam=i2c_arm=on,i2c_arm_baudrate=20000
Proof that we actually did reduce the i2c bit rate.
we now have proof that we can do a timeout inside a interrupt handler, and the time functions work.
#include <stdint.h>
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int IOUT = D6;
int IIN = D5;
int TOUT = A0;
/**
* @brief get the total time in ms since we started.
*
* @return total number of microseconds since we started.
* NOTE: this handles the roll over if called more than once an hour.
*/
uint64_t microsNow() { // time in microseconds...
static uint32_t lastNow_us=0; // check for overflow.
static uint64_t totalNow_us=0;
uint64_t delta_us;
uint32_t now_us = micros();
if (now_us >= lastNow_us)
delta_us = now_us-lastNow_us;
else // we rolled over..
delta_us = (0x100000000ull - lastNow_us) + now_us;
lastNow_us = now_us;
totalNow_us += delta_us;
return(totalNow_us);
}
void pinChangeInt() {
uint64_t start = microsNow();
uint64_t end = start + 1500; // 1.5ms timeout
digitalWriteFast(TOUT,1);
while (microsNow() < end)
;
digitalWriteFast(TOUT,0);
}
void setup() {
Serial.begin(9600);
microsNow(); // prime the pump...
// set "led" pin to be an output
pinMode(TOUT, OUTPUT);
pinMode(IOUT, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
// LOOP function runs in repeating loop (after setup finishes)
unsigned cnt = 0;
void loop() {
microsNow(); // and call this regularly... micros overflows every 71 minutes
ATOMIC_BLOCK() {
cnt++;
digitalWriteFast(IOUT, cnt & 1);
}
delay(10);
}
next prove we can reverse the io of the interrupt pin from inside the interrupt AND keep or re-enable the interrupt handler.
proof of concept we can detatch and retatch from the interrupt in the interrupt handler and reverse io direction AND have a timeout.
#include <stdint.h>
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int IOUT = D6;
int IIN = D5;
int TOUT = A0;
/**
* @brief get the total time in ms since we started.
*
* @return total number of microseconds since we started.
* NOTE: this handles the roll over if called more than once an hour.
*/
uint64_t microsNow() { // time in microseconds...
static uint32_t lastNow_us=0; // check for overflow.
static uint64_t totalNow_us=0;
uint64_t delta_us;
uint32_t now_us = micros();
if (now_us >= lastNow_us)
delta_us = now_us-lastNow_us;
else // we rolled over..
delta_us = (0x100000000ull - lastNow_us) + now_us;
lastNow_us = now_us;
totalNow_us += delta_us;
return(totalNow_us);
}
void pinChangeInt() {
uint64_t start = microsNow();
uint64_t end = start + 500; // 1.5ms timeout
digitalWriteFast(TOUT,1);
detachInterrupt(IIN);
pinReadFast(IIN);
pinMode(IIN, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
while (microsNow() < end)
;
digitalWriteFast(TOUT,0);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
void setup() {
Serial.begin(9600);
microsNow(); // prime the pump...
// set "led" pin to be an output
pinMode(TOUT, OUTPUT);
pinMode(IOUT, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
// LOOP function runs in repeating loop (after setup finishes)
unsigned cnt = 0;
void loop() {
microsNow(); // and call this regularly... micros overflows every 71 minutes
ATOMIC_BLOCK() {
cnt++;
digitalWriteFast(IOUT, cnt & 1);
}
delay(10);
}
timing of the detatch, read io and line reversal. So we should be able
Entirely in the interrupt.
#include <stdint.h>
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
int IOUT = D6;
int IIN = D5;
int TOUT = A0;
/**
* @brief get the total time in ms since we started.
*
* @return total number of microseconds since we started.
* NOTE: this handles the roll over if called more than once an hour.
*/
uint64_t microsNow() { // time in microseconds...
static uint32_t lastNow_us=0; // check for overflow.
static uint64_t totalNow_us=0;
uint64_t delta_us;
uint32_t now_us = micros();
if (now_us >= lastNow_us)
delta_us = now_us-lastNow_us;
else // we rolled over..
delta_us = (0x100000000ull - lastNow_us) + now_us;
lastNow_us = now_us;
totalNow_us += delta_us;
return(totalNow_us);
}
void pinChangeInt() {
uint64_t start = microsNow();
uint64_t end = start + 500; // 1.5ms timeout
digitalWriteFast(TOUT,1);
detachInterrupt(IIN);
pinReadFast(IIN);
pinMode(IIN, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
digitalWriteFast(TOUT,0);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
void setup() {
Serial.begin(9600);
microsNow(); // prime the pump...
// set "led" pin to be an output
pinMode(TOUT, OUTPUT);
pinMode(IOUT, OUTPUT);
pinMode(IIN, INPUT_PULLUP);
attachInterrupt(IIN, pinChangeInt, CHANGE,0);
}
// LOOP function runs in repeating loop (after setup finishes)
unsigned cnt = 0;
void loop() {
microsNow(); // and call this regularly... micros overflows every 71 minutes
ATOMIC_BLOCK() {
cnt++;
digitalWriteFast(IOUT, cnt & 1);
}
delay(10);
}
Great Ralph!
Should we be concerned at all about a 1.5 ms ISR?
On Sat, Jun 13, 2020 at 6:10 PM ralph bellofatto notifications@github.com wrote:
timing of the detatch, read io and line reversal. So we should be able
- detect the falling start condition,
- detatch the interrupt handler
- read the io
- poll the io pins for 1.5ms
- perform the i2c transaction
Entirely in the interrupt.
include
SYSTEM_THREAD(ENABLED); SYSTEM_MODE(MANUAL); int IOUT = D6; int IIN = D5; int TOUT = A0;
/**
- @brief get the total time in ms since we started.
- @return total number of microseconds since we started.
- NOTE: this handles the roll over if called more than once an hour. */ uint64_t microsNow() { // time in microseconds... static uint32_t lastNow_us=0; // check for overflow. static uint64_t totalNow_us=0; uint64_t delta_us; uint32_t now_us = micros(); if (now_us >= lastNow_us) delta_us = now_us-lastNow_us; else // we rolled over.. delta_us = (0x100000000ull - lastNow_us) + now_us; lastNow_us = now_us; totalNow_us += delta_us; return(totalNow_us); } void pinChangeInt() { uint64_t start = microsNow(); uint64_t end = start + 500; // 1.5ms timeout digitalWriteFast(TOUT,1); detachInterrupt(IIN); pinReadFast(IIN); pinMode(IIN, OUTPUT); pinMode(IIN, INPUT_PULLUP); digitalWriteFast(TOUT,0); attachInterrupt(IIN, pinChangeInt, CHANGE,0);
} void setup() { Serial.begin(9600); microsNow(); // prime the pump... // set "led" pin to be an output pinMode(TOUT, OUTPUT); pinMode(IOUT, OUTPUT); pinMode(IIN, INPUT_PULLUP); attachInterrupt(IIN, pinChangeInt, CHANGE,0);
} // LOOP function runs in repeating loop (after setup finishes) unsigned cnt = 0; void loop() { microsNow(); // and call this regularly... micros overflows every 71 minutes ATOMIC_BLOCK() { cnt++; digitalWriteFast(IOUT, cnt & 1); } delay(10); }
[image: SDS00002] https://user-images.githubusercontent.com/38866041/84579995-e1a0b600-ada0-11ea-82ae-7f124db8ce3c.png
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/GlobalVent/wiki/issues/138#issuecomment-643684591, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAOIMRMECWJNQ3HI5RE63TRWP2NJANCNFSM4NR26O7Q .
@alcohen since the photon is not doing anything else and appears to be still functional even with holding the interrupt for this long, I think we are ok.
The underlying gas simulation should be ok with this too. It is designed to not rely on a fixed simulation time interval, as is the control algorithm in on the pi.
More to the point, when using this platform for simulation, both the CPLD and the rpi need to slow the i2c bit rate down to 20Khz, rather than the default 100Khz.
As a result the minimum polling loop to get data will be a bit longer than the 12ms target that we originally had.
We have 3x10 bit times to send off the commands to retrieve the data and 910 bit times to pickup the data and periodically we have another 210 + 6*10 bit times to read temperatures on top of that.
in between each of those we have a 10ms delay. if we are careful to overlap things. I think that will end up with a data collection rate of around 16ms when doing simulation.
@stephmusinsky This study also implies that you need to slow down the I2c clock to be able to test in this mode (in addition to changing to the i2c address).
We also have to fit in a lower frequency temperature. collection for the two pressure sensors. I think we can accommodate this by adding a trigger for pressure collection at times we know that are not significant, for example, right after we close the valves for the reservoir and are waiting for the inhalation cycle.
We have this issue anyway, even with the faster i2c speeds as we have to accommodate the 10us delay between triggering the temperature data collection and retrieving the data.
The Photon OS overhead, time it takes to some of the required operations and interrupt jitter on the photon seems to have surprised all of us here.
But i believe i have a path forward.
@alcohen P.S. I think i may just have re-invented a way to characterize Internet of things real time response and suitability for use in devices.
I do believe i have the information that should allow me to complete this design.
I'll need to verify that the pins for the DCA are compatable with taking interrupts, otherwise, it is time for the Xacto knife and yellow wires.
checking pin outs and interrupts:
PhotonNot supported on the Photon (you can't use attachInterrupt on these pins):
D0, A5 (shared with SETUP button)
No restrictions on the Photon (all of these can be used at the same time):
D5, D6, D7, A2, WKP, TX, RX
Shared on the Photon (only one pin for each bullet item can be used at the same time):
D1, A4
D2, A0, A3
D3, DAC
D4, A1
We need A0 and D2 according to the schematic to capture the start condition. the above doc says we can't point to an interrupt at the same time.
Fortunately this board has all the traces on the surface... so we should be able to cut and rewire
The board will work until we need to use it with the CPLD at the same time, Then it will need some minor surgery. I would suggest here.
Cut the two traces and then do a cross over to the vias.
I already did the interrupt comparisons and surgery. Look at the text that's just below the frame in your screenshot of the schematic. A0 is bridged to A4 so that A4 can be used instead - you can even see the dotted line showing the connection, right there.
@dcstraney ok, i see it, then i only need to do bridge across two pads...
Ok, i'll set the software to use A0 and A4.
also i'm a little confused what is going on with this:
since this design is doing 2 i2c slave devices, it is going to have to do the same dca interrupt for both the clpd slave as well as the rpi slave, otherwise, when we are servicing one it will miss the other.
so, time to design the top interrupt handler and the exit and timeout conditions.
design point for the next step. I need an interrupt handler that *.checks for a start event on either device
once we have a start event we should be getting data back to back regularly.
note about I2c speeds. we can reprogram the i2c speed down to
dtparam=i2c_arm=on,i2c_arm_baudrate=10000
going to 5000hz oddly resulted in a 333khz
dtparam=i2c_arm=on,i2c_arm_baudrate=5000
So this puts a lower limit on how slow we can run this to debug the logic and get debug telemetry.
testing looks like we can go down to (8Khz, before it reverts to 333khz...
It is actually somewhere around 7530 hz, but 8k is close enough and divides nicely
well, thats good to know...
@dcstraney @alcohen ok, here is an interesting problem, the rpi has problems booting when i have the photon connected via its usb cable...
It worked for a while, but now it won't boot up if the from a complete power shut-down
I can boot up the rpi and then connect to the usb on the photon and it appears to be ok.
and I can initiate a software reboot, but cycling the power while the photon is connected via the usb does NOT work.
interesting...
create a base i2c slave class and state machine for the photon to be able emulate 2 sets of 3 i2c devices.
Eventually these drive classes that emulate each i2c device.