2
\$\begingroup\$

I'm currently designing a circuit based on a STM32F722ze (datasheet, reference manual).

As far as I understand from section 3.11 of datasheet and 10 from reference manual, for each "external interrupt channel" (EXTI0 to EXTI16), I can choose exactly on pin (for EXTIx, I can pick whatever the pin #x from any port).

So as far as I understand, I can only get 16 external interrupts in total.

Do you know if it is somehow possible to get more interrupt pins (even if it requires to read a few pins an check the differences manually to know which one generated the interruption)?

The ideas I have:

  • connection several pins to the same EXTIx (for example connection PA0, PB0 and PC0 to EXTIO) and when an interrupt occurs check which pin(s) changed since last interrupt. If I understand right, this is NOT possible on STM32F722

  • have an interrupt on any change on a given port (for example if any pin between PA0 and PA15 changes), and comparing to previous state to know which pin(s) changed. If I'm not mistaken, this exists in the ATmega microcontrollers: I haven't read about it for STM32 microcontrollers yet, but maybe I just missed it?

  • the "hardware" way: XOR all the pins I want to use as interrupts and put the XOR on a EXTIx pin, and use normal GPIO_inputs for all the individual pins: that way, I know each time a pin changed, and I can then check which one by reading all of them. (NB : it might be wiser to use several EXTIx pins, each XORing the pins of one port, as to speed up reading/comparison). One drawback is that if 2 pins change at the same time (i.e. faster than what the XOR + interrupt can react), there will be no interruption generated.

  • other ideas?

EDIT: for context, why do I want so many interrupts?

I'm developping a robot for cave exploration, that will navigate within narrow cracks (to narrow for humans to pass through), pushing against both walls to avoid falling into the bottom of the crack. For this, I use 8 arms (4 on each side) with a wheel at the end. For each arm, I need one motor for the wheel and one motor to move the arm and press it against the wall.

For the 8 wheels motors, I will probably soon add quadrature encoders in order to 1) detect motor stall (in adition to current measurement) 2) insure same speed on all 8 motors 3) get an estimation of the distance the robot made in the crack (which is an important factor, as the main goal of the robot is to know for how long one would need to enlarge the crack in order for humans to pass). So 8 motors * 2 signals = 16 interrupts.

So just for with the wheel motors, I already use all the interrupts I have.

For now, I'm not sure if I will need more, but as the PCB will be quite expancive already, I would like add extra connectors for adding aditionnal features as the development of the prototype advances. For now, one use for additionnal interrupts would be to measure the position of the arms with encoders (for now, it's done with potentiometers, which are not very accurate). Other uses might come that I'm not thinking of yet.

So if it is too complicated, I will stay with the 16 interrupts, but if there is a simple enough solution, I'd rather plan some more now.

For the quadrature encoder interrupts, it's the edges I'm interrested in, that's why I was suggestion to XOR the interrupts. NB : if having 2 changes at the same time occure but seldomly, it's still OK (if I miss 1% of interrupts, it will only result in 1% of distance error, which is far bellow the error due to other reasons (wheels sliping, non parallel walls, ...).

For other type of interrupts (like faults or sensor data ready, I agree that ORing or ANDing might be more usefull).

EDIT 2 : Maybe I'm thinking the problem the wrong way : maybe I can find some dedicated ICs to manage the encoders instead of getting all the interruptions directly on the STM32. That way I dont need all those interruptions pins, and I save a lot of CPU time on the STM32

\$\endgroup\$
11
  • \$\begingroup\$ Usually it is achieved by some external interrupt controller. It has a whole bunch of input pins, an output pin which is connecting to the ext pin of the target processor and a control interface. So this interrupt controller can be programmed to trigger the ext interrupt on the desired input pin changes and then the information about specifics can be read from it's registers via the control interface. See en.wikipedia.org/wiki/Programmable_interrupt_controller \$\endgroup\$
    – Eugene Sh.
    Dec 15, 2021 at 18:27
  • \$\begingroup\$ Before I answer, would you please describe why would you even need more than 16 external interrupt pins? What will you use them for? \$\endgroup\$
    – Justme
    Dec 15, 2021 at 18:39
  • \$\begingroup\$ You can not XOR all the pins, if two changed at the same time you'd miss both. BUT you can OR all the pins together, then check the pins in the ISR to see which one triggered the interrupt. \$\endgroup\$
    – Aaron
    Dec 15, 2021 at 18:56
  • \$\begingroup\$ @EugeneSh., actually it's hardly ever achieved by an interrupt controller IC, like the 8259 used in early PCs. Multiple interrupts are usually combined into 1 active-low interrupt pin using a wire-ANDing, wire-ORing if active high (less common). That technique was/is used in thousands of designs. Interrupt requests may be open-drain, ready for tying to a pull-up resistor, or made open-drain with an 0.3V signal diode, or go into a wide AND gate. By design, dedicated interrupt controller ICs are rarely used. \$\endgroup\$
    – TonyM
    Dec 15, 2021 at 18:56
  • 1
    \$\begingroup\$ @0___________ : the problem is that I have 8 encoders, but only 6 timers with encoder decoding features (TIM1 to 5 + TIM 8). If I had only 2 or 4 encoders as on a "normal" robot, it would have been the best solution indeed. \$\endgroup\$
    – Sandro
    Dec 16, 2021 at 13:59

3 Answers 3

1
\$\begingroup\$

Cool project!

A quadrature encoder has 2 output signals. If you want to process it in an interrupt routine, you can use 2 interrupts, but you can also use just one.

If one signal is clock and the other is direction, then you only need an interrupt on clock, with code to check the value of the direction signal. So you don't need 16 interrupts, just 8.

Having interrupts on both pins would double the precision, but at 4000 pulses/turn, on a slow moving cave robot, it won't matter: you'll have more than enough precision already.

You can also do it on a timer interrupt, of course. Cortex interrupt overhead is pretty low.

Likewise, your timers can do quadrature decoding. Have you checked how many encoders each timer can handle? It could be a lot more than just one, so I doubt you need 8 timers.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks! Just using one interrupt will devide the resolution by 2, but it sould't be any problem. And if I want to save CPU, I could even decide to go only for rising edges (CPU time /2, but resolution again /2). For the timers with quadrature decoding, there seem to be only 6 (TIM 1 to 5 + 8), and they seem to be able to handle only one encoder each (logic, as a timer is based on a up/down counter, and to handle 2 encoders one would need 2 counters \$\endgroup\$
    – Sandro
    Dec 16, 2021 at 14:08
  • \$\begingroup\$ I've had hundreds of thousands of irq/s on a Cortex-M0 running at 204 MHz and it didn't care, so I don't think you'll have any problems with your much more powerful cpu. \$\endgroup\$
    – bobflux
    Dec 16, 2021 at 14:13
3
\$\begingroup\$

There's many ways of building your system. My first observation is that you might have fallen into a common misconception for interrupts: "if I want to respond to an asynchronously changing signals, I connect them to an interrupt input".

There are other, more efficient ways to solve your problem. You don't state your RPM, and therefore each encoder's rate of change so you'll have to take these as examples of principles.

For example, you can use a regular interrupt to sample all your encoder inputs, say, every 100 us, and process them.

That gives you 10,000 samples/sec of the encoder positions. Your CPU can still do other work. I have done just that for a 16-channel motor board using cheaper, slower original PICs. At the start of your timer Interrupt Service Routine (ISR), it would read all motor inputs into RAM and update the motor outputs from RAM. That ensures I/O changes happen on crisp boundaries. The ISR then processes the inputs, prepares new output values, stores them in RAM and exits. With a high-MHz MCU, you can get a lot done or slow the interrupt rate if the quadrature encoders and motors don't need it.

These interrupts are related to time, not to encoder changes. The time interrupts can relate the changes in the encoder outputs to speed very easily. An interrupt triggered by an encoder change would have to work backwards to relate that one encoder output to other encoder outputs, then to to time, to work out speed and direction.

You can use the on-chip timer motor quadrature decoders if you have enough.

You can use a cheap CPLD (£5 or less) to implement simple speed control with quadrature feedback over, say, an SPI management link with your MCU. You'd need to be competent in HDL development to make a good job of it. But it's the option with most channel capability. You just add more motor control circuits in parallel with each other. That'd be my own preferred option, offloading the donkey work to simple parallel circuitry where possible.

So there are various methods, each to be traded off against each other. Using piles of interrupts isn't a particularly scalable solution. Had you thought about what each ISR would actually be doing, how you'd cope with late/missed interrupt servicing because of so many happening and so on.

If you use the timer ISR, your quadrature decoding software can use the following technique:

  • Sample 2-bit quadrature encoder outputs
  • Combine with 2-bit quadrature encoder outputs from last pass
  • Use 4-bit value an index into jump table (C switch clause)

Each of the 16 possibilities has a handler. Some are null e.g. 0000, 0101, 1010, 1111 all mean 'no change'. Others produce your decoded result. It's fast and tidy.

\$\endgroup\$
3
  • \$\begingroup\$ Indeed, the more I think about it, the more it seems that interruption are no longer the right way to go for that many encoders. I haven't yet the exact specs of the final motors (for now, for the first tests, I'm using 60rpm motors without encoders from aliexpress), but I think I will remain in the same order of magnitude. If I take the same with encoders (and interpret correctly the very poor "datasheet") , then I will be arround 4000 pulses/turn, so arround 4000 pulses/s if I stay at 60rpm ). So 16 000 changes/s, so I think something like 30k or 40k samples per second should do \$\endgroup\$
    – Sandro
    Dec 15, 2021 at 21:59
  • \$\begingroup\$ For on-chip quadrature decoders, I'm far from having enough (the datasheet mentions them for only 4 timers (2 to 5). And anyway, even if 4 other timers turn out to be capable as well, I can't spare 8 timers (or at least, it would require me to turn to soft PWM instead of hardware one). For using CPLD, it might be a solution, but I fear it will require quite some learning (even if I used a couple of FPGA dev boards before) \$\endgroup\$
    – Sandro
    Dec 15, 2021 at 22:06
  • \$\begingroup\$ @Sandro, quadrature decoding can easily be done by your timer interrupt. Will add a technique to my answer. \$\endgroup\$
    – TonyM
    Dec 15, 2021 at 22:21
2
\$\begingroup\$

There are only 16 EXTI interrupt sources, and even then, there is only 7 separate EXTI interrupt vectors to handle them.

But of course many other peripheral can be configured to trigger an interrupt from an external source, such as the timers. Input capture feature could be used to turn all timer capture channels into external interrupt sources.

For quadrature encoders, the timers actually have quadrature encoder mode. So it makes no sense to try counting quadrature encoder position with external interrupts, as you have the peripheral doing this for you.

So since your requirements are quite special, maybe it would be better to have a chip that can handle the encoders for you, so you don't have to use interrupts to track the encoders yourself. Use a right tool for the job, you know, if you only have a hammer, all problems look like nails. External interrupts don't sound like a correct way to handle this any more.

\$\endgroup\$
2
  • \$\begingroup\$ On robots with only 2 encoders (usually arduino based), I usually just used interrupts, but it's true that with 8 encoders it's quite a heavy load to process (but if a ATMega @ 16MHz manages 2 encoders, a STM32 at 260MHz should be able to manage 8). For the solution using timers, I've seen it, and it looks nice, excepted that I haven't got 8 timers to spare (it's just not planned that there are that many). Using specific ICs to handle the encoders is probably the good way to go. I will look for them. Thanks a lot! \$\endgroup\$
    – Sandro
    Dec 15, 2021 at 20:12
  • \$\begingroup\$ Sure but most likely your application does other things as well as handles 16 external interrupts, and any missed interrupt will cause the count to be wrong. And you don't need 8 timers, you need less than 8 timers, as they generally have multiple timer channels - if you just want the interrupts. \$\endgroup\$
    – Justme
    Dec 15, 2021 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.