STM32 MCUs and the right pick

Ollie
Posts: 197
Joined: Thu Feb 25, 2016 7:27 pm

Re: STM32 MCUs and the right pick

Post by Ollie » Sun Jun 04, 2017 4:45 pm

@MiniMe,

Indeed, I did use Teensy 3.2 for 2 motor control and Teensy 3.5 for 4 motor control. I couldn't use Teensy 3.6 because the DC motor driver (vnh2sp30) is using 5V logic and the level converters didn't work with 5 V non-tolerant pins - especially with the high current required for the frequency input.

I don't recommend the usage of TIM based quadrature encoders. You will get very reliable position information, but you are losing accurate speed measurement. I am using interrupts with built-in logic based on the number of encoder magnets. That allows very accurate speed reading on every edge. F407 has enough computing power to tolerate the interrupt load for 6 motors.

You are very right that the jitter in PWM signal is causing some disturbances in the control loop. FFT is a proper tool to highlight those impacts. Please take a look of the new DShot technology. It allows non-drifting digital control for the analog signals. It is already widely used in quadcopter races where extreme control speed is required.

Cheers, Ollie

User avatar
Pito
Posts: 1627
Joined: Sat Mar 26, 2016 3:26 pm
Location: Rapa Nui

Re: STM32 MCUs and the right pick

Post by Pito » Sun Jun 04, 2017 6:41 pm

Pukao Hats Cleaning Services Ltd.

minime
Posts: 20
Joined: Mon Feb 13, 2017 11:10 am

Re: STM32 MCUs and the right pick

Post by minime » Sun Jun 04, 2017 7:32 pm

@Ollie

Teensy 3.5 has high 13bits adc which is valuable feature i can not forget, i will compare the stm32 adc stability if not less to teensy 3.5 , yes I agree looks like the F407 is a good choice and also much cheaper. will order a dev board from ebay and check it out.

I will read more about the DShot to understand it's current limitation to F3 and F4 , just working to customize my cnc machines with mach3 might really incorporate that also in away.

would highly appreciate sharing some code if possible you made if used with stm32duino.

https://www.youtube.com/watch?v=5DL4eoJQ_zc

dannyf
Posts: 167
Joined: Wed May 11, 2016 4:29 pm

Re: STM32 MCUs and the right pick

Post by dannyf » Sun Jun 04, 2017 7:43 pm

to test just how much a typical encoder read routine would drain out of the processing power, I ran the following code on a PIC24:

Code: Select all

volatile int16_t enc_cnt=0;					//encoder counter

static const signed char encoder_states[]={0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};

//encoder routine
//+1->clockwise, -1->counter clockwise, 0->invalid
void enc_read(void) {
	//static unsigned char encoder_output=0x00;
	static unsigned char ABs=0x00;			//AB key read out, Previous in the high 2 bits and current in the low two bits;
	//unsigned char tmp;

	ABs = (ABs << 2) & 0x0f;				//left 2 bits now contain the previous AB key read-out;
	//tmp=IO_GET(port, pin_a | pin_b);		//read ab pins
	if (digitalRead(ENC_CHA)) ABs |= 0x02;	//set the 1st bit if A is high now;
	if (digitalRead(ENC_CHB)) ABs |= 0x01;	//set the 0th bit if B is high;
	//ABs &= 0x0f;							//only retain ABs' last 4 bits (A_previous, B_previous, A_current, B_current)
	//encoder_output += ABs_states[ABs];	//return encoder_output;			//return the absolute value
	//return encoder_states[ABs];			//return the relative value (+1 = clockwise, 0, -1 = counterclockwise)
	enc_cnt += encoder_states[ABs];

	//flip led2 - for measurement
	digitalWrite(LED2, !digitalRead(LED2));
}

void setup(void) {
	//user setup code
	pinMode(LED1, OUTPUT);					//LED as output
	pinMode(LED2, OUTPUT);
	
	//configure CN interrupts / pins
	attachCNInterrupt(enc_read);			//install encoder reader as the isr handler
	activateCNInterrupt(27, CN_WPUEN);		//CN27/RB5 activated with weak pull-up
	activateCNInterrupt(24, CN_WPUEN);		//CN24/RB6 activated with weak pull-up
}
	
void loop(void) {
	//digitalWrite(LED1, !digitalRead(LED1));	//flip led1 - for debugging
	//delay(10);
}
the code is entirely interrupt based -> the main loop is empty.

It took away 3.3% of the processing power of a 16MIPS PIC24 to read an encoder generating pulses at 1Khz, or 60Krpm., vs. 2.5% per the estimate earlier.

the code can be easily expanded to support more channels, or even at higher speed.

Ollie
Posts: 197
Joined: Thu Feb 25, 2016 7:27 pm

Re: STM32 MCUs and the right pick

Post by Ollie » Sun Jun 04, 2017 8:16 pm

That is the nice code for state transition based decoding. I am using more brute force method on Teensy. Without doing analysis, my guess is that the brute force is faster.

This code demonstrates how the performance counter (DWT_CYCCNT) is used for most accurate timing reference.

Code: Select all

void intENC1_A() {
    enc1.currentRef     = *DWT_CYCCNT;

    if (digitalReadFast(ENC1_A)) {
        (digitalReadFast(ENC1_B)) ? enc1.currentCount++ : enc1.currentCount--;
    } else {
        (digitalReadFast(ENC1_B)) ? enc1.currentCount-- : enc1.currentCount++;        
    }
    if ((enc1.currentCount % EDGES_PER_ROT) == 0) {
        enc1.startRef   = enc1.endRef;
        enc1.endRef     = enc1.currentRef;   
    }
}

void intENC1_B() {
    enc1.currentRef     = *DWT_CYCCNT;

    if (digitalReadFast(ENC1_B)) {
        (digitalReadFast(ENC1_A)) ? enc1.currentCount-- : enc1.currentCount++;        
    } else {
        (digitalReadFast(ENC1_A)) ? enc1.currentCount++ : enc1.currentCount--;        
    }
    if ((enc1.currentCount % EDGES_PER_ROT) == 0) {
        enc1.startRef   = enc1.endRef;
        enc1.endRef     = enc1.currentRef;   
    }
}

This is old code, where the accurate speed is calculated only once per rotation. In the F407 code, the speed is calculated on every edge. The new code allows to use different motors with different magnet counts.

minime
Posts: 20
Joined: Mon Feb 13, 2017 11:10 am

Re: STM32 MCUs and the right pick

Post by minime » Sun Jun 04, 2017 8:34 pm

@dannyf

yes i am familiar with this algorithm , also used the same concept with esp32 but managed to have only one encoder working with 2 interrupts , also found this link https://github.com/bubulindo/STM32Encoder will check it out.

dannyf
Posts: 167
Joined: Wed May 11, 2016 4:29 pm

Re: STM32 MCUs and the right pick

Post by dannyf » Sat Jun 10, 2017 1:27 pm

the speed is calculated on every edge.
that's not difficult to implement, so long as you define "speed" to mean transitions in a given period of time.

One way to go it is to increment a counter in the encoder piece, and stamp it with the current time.

Code: Select all

  enc_counter++;						//increment enc counter
  if (enc_counter==0) enc_time = time_now(); 	//stamp the count on roll-over
  //alternatively, you can calculate time it takes since last roll-over, like this
  //if (enc_counter==0) {delta_time = time_now() - enc_time; enc_time = time_now();}		//delta_time is how long it takes for the enc_counter to roll over.
  
time_now() can be millis(), micros(), or ticks(), depending on your application.

and in your code, you just need to take current time and (time_now() - enc_time) / enc_counter is the (average) time it takes to advance the counter since its roll-over last time.

Ollie
Posts: 197
Joined: Thu Feb 25, 2016 7:27 pm

Re: STM32 MCUs and the right pick

Post by Ollie » Sat Jun 10, 2017 3:45 pm

@Dannyf,

The trick in calculating the speed in every edge is to store all the previous edges around the full turn. At minimum, there are 4 edges that are not evenly distributed due to differences in hall sensor mounting:
- rising A
- falling A
- rising B
- falling B

In addition of that, the rotating magnets are not guaranteed to be equal. I have done enough measurements to observe the differences. Measurements with ms or us ticks are too coarse for speed measurements. The CPU clock counter or a dedicated counter running over 50 MHz is required.

dannyf
Posts: 167
Joined: Wed May 11, 2016 4:29 pm

Re: STM32 MCUs and the right pick

Post by dannyf » Sat Jun 10, 2017 5:29 pm

The CPU clock counter or a dedicated counter running over 50 MHz is required.
I ran the following code on a 16MIPS Arduino:

Code: Select all

void enc_read(void) {
	static uint32_t ticks_prev=0;
	uint32_t tmp;
	//encoder logic above
	enc_counter+=1;					//increment the enc_counter
	if (enc_counter==0) {			//overflow has taken place
		tmp = time_now();				//take current time
		delta_ticks = tmp - ticks_prev;	//read the ticks
		ticks_prev = tmp;			//save current reading
	}
}
it is a one-ch speed counter, relying on the overflow of an 8-bit type (=enc_counter).

time_now() is a ticks() implementation that essentially returns (timer0_overflow_count<<8)|TCNT0, with their atomicity preserved.

When fed a 1Khz signal (equivalent to an encoder running at 30K pulses per minute), the above function returns a delta_ticks value of 32,000, just as expected, rock solid. the whole thing takes less than 0.3MIPS to run.

you can easily scale that up and realize that either with a lowly 8-bit mcu, you can count the lights out before reaching the mcu's limit.

minime
Posts: 20
Joined: Mon Feb 13, 2017 11:10 am

Re: STM32 MCUs and the right pick

Post by minime » Sun Jun 11, 2017 3:52 am

I have read many of your posts , very helpful indeed , Thank you very much.

Post Reply