Congratulations on your well written question loaded with information.
The answer to your question is in the opamp's datasheet:
MAX4352/MAX4353/MAX4354 are compensated for a minimum closed-loop gain of +5V/V
Your schematic sets the MAX4354 opamp for unity gain at HF via the feedback capacitors (C31 and the rest). Therefore it will oscillate, this is inevitable.
The fix is to remove all the 150pF caps.
Now, the amplifier will still be unstable, as explained in datasheet page 11 "Choosing resistor values". You really don't want a 10k feedback resistor on such a fast opamp, this will create a pole with the input capacitance, let's say 3pF or so including trace capacitance. This adds phase lag into the feedback, which will eat into the phase margin and either make it oscillate or screw up transient response and settling time, which I presume are important to you since you chose this fast opamp for a reason!
Considering the motor currents involved, you're not saving milliamps on the opamps' power supply, so you need lower feedback resistors. Try 1k/100R instead of 10k/1k.
Problem is, all the extra traces and pads for your unnecessary capacitors do add parasitic capacitance, so put the feedback resistors in whatever SMD footprint is closer to the IC (which will probably be the caps) and cut the traces to the unused footprint.
If it still gives you trouble, don't do another board revision yet. Just solder the feedback resistors across the MAX4354 pins, and cut more unnecessary traces to reduce capacitance. With 0402 resistors this should work just fine. If this gets your opamp rock stable, then you know your next board revision should have the resistors R33 and R24 (and their equivalents for the other opamps) as close to the pins as possible with minimum length traces.
But it will still suck on transient response, maybe ring, because the opamps are driving capacitive loads, which are the long traces to the microcontroller. I would add 15R to 33R resistors at the opamp outputs.
You could even use lower feedback resistor values, although the LM358 might start to bitch a little.
LM358 is a old piece of crap with crummy slow transient response. Your fast MAX4354 is drawing steep current pulses from its output. Output impedance of LM358 at high frequencies is "mmeeeehhhh" because it has 1MHz bandwidth.
Therefore ADC_MID is likely to move around. The fix is to have a look at the internal schematics of LM358 (datasheet page 13), notice how the compensation is wired, and stick a resistor between the output and ground (like 470R) to bias the output stage into class-A, which will lower its output impedance and make it faster.
If this is not enough and you notice transient variations on ADC_MID,
stick a big fat low-ESR cap right across the output of LM358, like 470µF 6.3V Panasonic FR which costs 9c and has 80 mOhms ESR. Or even a polymer cap. Opamps driving capacitive loads will be stable if the cap is large enough.
Other advice:
- Increase bypass cap values from 100nF to 1µF
- L2 will resonate with C42, download L2 spice model from murata simsurfing website, spice it, then replace C42 with cheap 105°C electrolytic with suitable ESR like Panasonic FC 100µF.
- Stick 1-2 MLCC in parallel with C26 right at the output of the switcher U4 to shunt HF noise at the source and reduce noise in your GND.
- Liberally spray the +24V rail with 100nF MLCCs, 1-2 per MOSFET, put them right next to the FET, you want to have a tight loop for the FET's HF switching currents.
- Bootstrap diodes D1 D3 D4 can be replaced by smaller cheaper and more important, lower capacitance models.
- I don't know how your micro handles its internal ADC reference, whether it needs to be bypassed by a cap, or if it has separate AVCC pin, you should check
Layout:
- R20 is a problem as it prevents you from shrinking the high di/dt current loops by returning currents from the other sense resistors to the GND pin of the three big capacitors. Thus, EMI. Since R20 provides a measurement which is redundant (it is the sum of the three currents which are already measured) it can be removed along with associated circuitry.
- This frees up an opamp which can now be used instead of LM358. It is not stable at unity gain though, so a little trickery is needed in the feedback network.
- The FET driver should be in the center of the board (there is an empty space) next to the FETs, which reduces the length of the gate traces, which reduces LC oscillations, which allows you to get rid of the zeners, you save money. Also this cuts crosstalk between the MCU PWM traces and the analog current measurement traces. Also this removes the gate drive traces which cut a large swath of the bottom ground plane out.
- Remove ground pour under micro or tie it down to ground plane with many vias. The main use of ground pours on toplayer is to make you forget to put a dedicated GND via for a component that really needs one (like that AGND pin) and increase noise. Ground pours are evil since they connect that sensitive AGND pin to the noisy GND pin of a decoupling cap. Ground pours on toplayer need to die.
- Add more vias, 2 GND vias per decoupling cap reduces inductance.
- The 2 slot antennas in the ground plane may be a problem
- Your opamps are wired as differential, the GND side of the sense resistor should be taken at the resistor, not at whatever potential GND is under the opamp. Thus, route the sense lines as a differential pair. Your CAD software
will want to connect your "GND" trace to the rest of the GND, so use a net tie, which is a virtual component allowing you to do this.
- The micro's ADC measures voltage in proportion to its internal ADC reference (is it the power supply? a VREF pin? check datasheet on how to handle this).
- ADC_MID is generated from a +3V3 which is not really the same as the micro's, so there will be an offset. This is solved by sampling the currents in the MOSFETs which are not turned on, which gives you the offset, and substracting in software. Time your ADC sampling points with your PWM. Your micro should know how to do this.
- C37 is a MLCC thus piezoelectric, ADC_MID will respond proportional to vibration and board flex. Also C37 value 100nF is too low. Use electrolytic cap instead.
- and most important, your ADC measures voltage relative to ITS OWN GROUND. Which is why R20 is trouble, as it routes the motor current all over the ground, destroying its integrity. The bottom pins of R44/C37 should sample the GND at the micro's AGND pin to fix this. Capacitor at the output of LM358 (if any) should also be grounded near this point.
Others:
- You have no height restriction, so tantalum caps are not your friend, in fact they are expensive little firebombs, good thing you don't use any. But aluminium caps are not obsolete! There is nothing wrong with putting a few on your board to stiffen up your +5, +15, +3v3 supplies. I like Panasonic FC, FM, FR, they're 105°C, very tough, small, cheap, reliable, with ESR low enough to offer superb decoupling performance, but still high enough to make your LDOs stable and not ring with MLCCs. Polymer caps ESR is too low, which is problematic, as they will ring with MLCCs and do evil things to LDOs, polymer caps need to be handled with care.
FYI by following these rules I did a board with 4 switchers, 1 micro, 1 H-bridge, everything switching all over the place, and I got less than one ADC LSB noise on the current sense resistor.
Best Answer
I only have one question for you:
Where is your ground plane?!
Of course your microcontroller is resetting. You don't have anything that can even be identified as ground. The poor microcontroller appears to be connected through the thinnest, needlessly long traces to a maybe a single decoupling capacitor that is too far away anyway, and that capacitor isn't connected to ground or anything else any better than the microcontroller is.
Your controller is resetting because, for all intents and purposes, it isn't even really grounded. This is powering a motor that sounds like it can peak at 2 horsepower, and that is almost entirely in the form of a inductive load, one split between several phases (coils), and worse, it is switching at kHz or more with fast rise times (I would guess).
And as the current voltage increases, you lose anything that one could call ground. Ground is a reference potential for the entire circuit, but to keep different parts of a circuit at the same potential, you need a good low impedance connection. If you don't then every part of the board that you intended to be ground will be at a different potential. There are currents flowing, and in your case, a lot of current, and that causes a voltage drop between different parts of the board just from the resistance of the traces. But in your case, there is also a lot of impedance that will compound the problem even more whenever there is a current or voltage transient. Which is all the time, since you're switching a lot of power all the time to control that motor.
You need as close to a solid ground plane as you can underneath the microcontroller, without any traces breaking it up. Them be sure to isolate it such that it makes exactly one low impedance connection to where ever the ground/negative wire or connection on your board is, then route all the high current power traces and grounds so they will not need to ever pass through the ground plane underneath your microcontroller.
And give that poor thing more decoupling capacitors, put them as close as physically possible (if you have a gap between the courtyard boxes of the microcontroller and capacitor's footprints, then they're too far apart), give it some bulk capacitance in the form of a small tantalum (the higher ESR actually acts as a snubber and will clean up the power a bit more). After doing that, your board stands a good chance of working since it seems to be right on the edge of working already. But you should read up on PCB layout, especially in the context of power switching and that sort of thing. You probably have some pretty nasty ringing transients which can potentially blow your switching elements if they're MOSFETs.
Working does not necessarily mean robust, especially when it comes to inductive loads like brushless motors. If you're going to do some dynamic tests by loading the motor, you might want to wear eye protection just in case. I've seen a 555 timer go off like a fire cracker, leaving nothing but the DIP pins sticking up from the board, flapping in the breeze where the body of the chip used to be, just because there was a small inductive load involved.
1kW is more power than you think, err on the side of caution until you know nothing on your board will vent unexpectedly (it happens to the best of us).