I think the best option is to use TCA in 16-bit single-slope PWM mode. Things I'm not sure about are (a) will this mess up other stuff in the Arduino? (I know it'll mess up the timing functions but I can live without those), and (b) how to achieve the alternating pulses of different durations. Maybe CCL could be used to do that.
I could implement the PWM in software but I want this device to be controllable by commands on the serial port and I'd be concerned about the time it takes to handle serial comms interfering with signal timing.
Before I dive in and maybe go wandering up a blind alley or two I'd welcome any suggestions and pointers to existing code that might be useful.
Do you want a variable frequency or can the frequency be fixed in the range of 0...300Hz ?
Why can the valves not deal with overlapping signals ?
Do you have a link to those valves ?
I have forgotten about the PWM modes, but others can make such signals with the hardware timers.
According to the blog below Timer B0 is used for one of the PWM outputs. Timer B3 is used for millis(), micros() and delay().
I have seen examples which change timer settings causing millis(), micros() and delay() to stop working properly, but the Arduino environment still works fine. As I understand it some libraries rely on these functions for timing.
Variable frequency, controllable by commands sent down the serial port. Frequency will not be varied while signals are being output.
They are being used to alternately inflate and deflate a pneumatic actuator; if they are both on together air will just bleed straight through.
With so low frequencies you don't need a hardware PWM. Just setup any unused MCU timer for desired frequency and turn your GPIO on and off in interrupt.
The work of millis() and micros() will not affected.
Update: I'm now leaning towards using the microseconds counter, polling it in a free-running loop. At the start of the first cycle the program will set output A, and read the micros() value and use it to calculate 4 event times:
Pulse A end time
Pulse B start time
Pulse B end time
Next cycle start time
Then in the loop read micros() and if we passed one of those events, set or reset the appropriate port line and if necessary start the next cycle.
Handling serial comms will cause a little jitter in the pulse edges but that's acceptable.
That sounds like you are using micros() to calculate future time stamps. That is a no-no as far as micros() rollover, you will see timing errors if you do that. But I would have to see your code to be sure.
O, I was wrong. Sorry for that. In "boards.txt" the "MILLIS_USE_TIMERB3" is indeed defined.
If you stop millis() and then run into problems, then we can not help you It is not just a few libraries, it is really a part of the Arduino system.
A valve that can switch at 1000Hz ? Now I understand the variable frequency and the problem with overlapping.
I agree, using a micros() timer is a good start.
If I have some spare time and you have a test sketch, then perhaps I can use a Logic Analyzer for the signals in the Wokwi simulator.
Here's a test of the double width PWM using the micros() function. It works well; loop time is about 20us. I'm using unsigned longs for all time values so (I think) overrun of the micros() value should not cause a problem.
If you add more code, then there might be more jitter/delay in the output.
Wokwi does not have the Nano Every, so I used a Arduino Uno.
I have PulseView installed on my computer and Wokwi has a simulated Logic Analyzer which stores the data on my computer.
PulseView has decoders to analyze the signals:
Yes there will be, although it is not too important in this application. A stable and accurate frequency is more important, and using the overrun variable (="how late am I?") takes care of that.
Thanks for introducing me to Wokwi. Debugging code on Arduino is a PITA, so I'm sure I'll be using it a lot!