So I spent quite a bit of time figuring this out and I thought I would leave a detailed answer for others. First, thanks for all that replied. I made a bad assumption about how the PWM signal works in the SparkMax. It is a bit different than what we use professionally for high end motor control, LED dimming, etc.
Problem one I encounter is the Vih (Voltage input high) is greater than 3.3V. So you need to drive that PWM signal with a 0 to 5V signal. I had some N-MOS FETs laying around, which I was able to use. But if you use an N-MOS FET, it will invert the signal, so make sure you invert the duty cycle of your PWM signal as explained below.
Will Toth, posted a really good picture above. The SparkMax has the following interface via the PWM input:
What this is saying is the time between pulses must be 50 Hz (20 ms) to 200 Hz (5 ms). Then a neutral motor is a pulse width in the range of 1475 to 1525 us. Or put a different way. If we pick 100 Hz as your frequency (period in PWM parlance), then the neutral duty cycle is 1.5 ms / 10 ms or 15% duty cycle. If you generate a 100 Hz (10 ms period) PWM signal with a duty cycle of 15%. You will get a neutral (stopped) motor. Now if you increase the duty cycle from 15% to 20%, the motor will go from stopped to 100% speed in the forward direction. Likewise, if you reduce the duty cycle from 15% to 10%, it will go from stopped to full reverse.
Lets look at some pictures. It is REALLY hard to see the difference from the pictures, so look at the +width value. This is what a neutral signal looks like:
No if we slightly increase the duty cycle of the PWM signal to 1540 microseconds or 15.4% duty cycle, the motor should start to spin.
As we increase the duty cycle of the PWM signal, the motor will increase in speed until we hit the max:
If we want to spin the motor in reverse, you need to decrease the duty cycle from 15% to something less. The image below shows full max speed in the reverse direction:
As others have said. I would NEVER use the PWM signals to control motors via the Spark Max on an actual robot. We always use CAN. It is more robust, insensitive to EMC noise, much more flexible, and easier to use.
As far as development environments go, you can use anything that generates a PWM signal. Someone mentioned Ardiuno. I personally like Pi Pico’s running Micropython. They are super easy to use, setup, debug, etc. Or full blown Raspberry Pi’s, which can be a bit more difficult to setup and use. I have used Linux professionally for over 20 years, so they feel like home to me.
I hope that helps others.