Welcome! Log In Create A New Profile

Advanced

Software phase, ARM Cortex_M3 STM32 based highly integrated control board.

Posted by grael 
Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 11, 2009 03:09AM
Background:
On the first day of this year (1/1/2009), I made a personal commitment to build myself a CNC machine.

(Please bear with me now, there is some hardware discussion that ought to go here for the record, and as background for the software design phase.)

There are many options for control of CNC additive , subtractive, or scanning control electronics, Zack's modular board designs ( [www.makerbot.com] ), and various other open source designs.

The mechanical stuff is easy for anyone who has a modestly equipped workshop, and I had a 3-axis platform built within a couple of weeks.

Next, I had to drive it.
At that time, REPRAP.org were going through a transition, led by Zach, from generation 2, to generation 3 open source electronics, and there was a parts shortage over the transitional stage. Never the less, I enquired about pricing, and got a New Zealand price quoted ( I think for generation 2 ), of NZ $360 for a complete set of circuit boards with components.

Adrian Bowyer has done amazing things in motivating, and achieving things with the reprap machines, and growing the community, but, I believe, because of the way he has done it, the RRF "products" to date, have been educational institution oriented. In such an environment, the teacher to student ratio is very low (compared with industrial scenarios), and a modular approach is sensible. This approach has persevered while Zach was leading innovations for the RRF under his mostly volunteer work.

However, to me, in reviewing the development history as an outsider, and one with previous business and engineering experience in hardware and software engineering, there were some design flaws from my perspective in the favoured modular approach:

As with "Integrated" circuits, integrating much functionality onto one circuit board reduces:
-Potential faulty connections
-Cost of inter module connectors
-PCB header footprint space
-Wiring loom volume
-Assembly labour

While detractors may well point out that modularity allows for easy component replacement, it's really a better design philosophy to design for robustmess in the first place.

Some detractors might also argue that a modular system is better at coping with unforseen circumstances, you can just design a new module.

So, with all this in mind, I considered the quoted price, the value for money, and decided that I could make a better circuit board.


This is how I met the challenge:


On January 31, 2009 07:01PM, I started a build thread on the electronics forum:
[forums.reprap.org]



Back to this thread, in the software forum:
As of this last weekend, I'm writing software for it.

Here's a summary of the features I designed in, and that actually made it to the final circuitboard:


(A) 4 axis stepper motor control, 2 amps continous rating, 4 amps max, protected by polyswitch fuse (triggers at 3A, resets at 1.5A) Each output has 0Volt and 12Volt pins available on the header, in case a boost stage is required for a bigger machine.

( B ) 4 axis limit detection.

(C) 5 channels designated for servo motor control, although they can be reused as general purpose signal outputs, digital inputs, or analogue inputs.

(D) RS485 communications via 3 way terminal block.

(E) I2C communications header.

(F) RS232 serial boot loader port, also available for debug and/or normal communications.

(G) USB port, for high speed PC communications.

(H) SD Card slot, for stand alone operation.

(I) 2 x optical encoder pair inputs. (i.e. monitoring of two arbitary axis, or 4 x speed inputs.)

(J) Two analogue inputs reserved for Temperature monitoring.

(K) LCD 4-wire + control interface.

(L) 2 x status LEDs

(M) Piezo, direct driven from microcontroller, for audible feedback.

(N) 5 x Darlington transistor outputs, good for 5 amps intermittant, or sustained if heatsinked.

(O) 7 x control push buttons

(P) Reset Button.

(Q) Power up configuration jumpers x 2

(R) 12+5 volt hard drive molex connector to power circuit board

(S) Current sense resistors on each motor winding per stepper motor driver, this allows for analogue motor stall detection, as I wired these to the microcontroller, on analogue inputs

I'm not far along on software yet,
So far, I've only established PC communications and sent some simple test programs into the ARM microcontroller, but I have a platform I'm happy to work with !smileys with beer

For those of you who look at the options available on this board and feel overwhelmed,
It can be made cheaper !
You can populate for only three axis, not connect servo motors, not connect many of the components, and it will still do the basic functionality of a reprap-like machine.
>grinning smiley<
(PCB makers actually DO charge for holes, but you gain on the volume production price reduction)drinking smiley

Edited 3 time(s). Last edit at 05/11/2009 03:25AM by grael.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 11, 2009 10:34AM
I've been following your thread for a while now and I must say I'm impressed and looking forward to seeing your board driving machines!

I was wondering what software/toolchain are you using to write/compile/upload code to the ARM? I've got a couple Cortex-M3s (just the microcontroller/breakout boards) I've been thinking of coding for, but just haven't had to time to research them.

Thanks and good luck with the software.

Edited 1 time(s). Last edit at 05/11/2009 05:13PM by Jeff.


----
[www.binaryconstruct.com]
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 12, 2009 03:02AM
jeffpark_ Wrote:

> I was wondering what software/toolchain are you
> using to write/compile/upload code to the ARM?
> I've got a couple Cortex-M3s (just the
> microcontroller/breakout boards) I've been
> thinking of coding for, but just haven't had to
> time to research them.

Hi Jeff,
I've been using the tool chain that came with the STM circle first version, by Raisonance.

I think it's out dated by now.
Initially, I tried using the version 3.0 off STM's web site, but I'm so new to programming in C, that I got caught out straight away, and couldn't successfully assemble anything. I think the problem was incorrect library directory, Raisonance using it's default, when the higher level files were expecting to work with ones I had in a subdirectory off my project, but hadn't explicitly told RIDE about.

I eventually copied a raisonance project, cleaned it up a bit and got some LEDs working on my board.

I'm having trouble though, modern code examples don't work, because some of the register definitions are subtly different. Things like using the BSRR register with GPIO ports, the examples on the STM32 forum website don't work with my set of include files. I tracked down a set of BSRR related macros last night to an IO .h file, in a raisonance folder. It's very time consuming tracking this sort of thing angry smiley , especially when I'm new to C too, because it takes me longer to pinpoint syntax errors versus bad variable definitions.

Graham Daniel.

P.S. If you have a demo board, I would probably run with that set of files... unless you are doing a huge project.

Edited 1 time(s). Last edit at 05/12/2009 03:06AM by grael.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 12, 2009 12:20PM
I just have a header board of a cortex-m3 and an old parallel jtag interface with no software. I've got some experience with embedded systems but mostly with FPGAs and DSPs a few years ago so I'm a little rusty. On the other hand I work with C++ daily. It just seems like every time you switch to a new MPU there is a huge learning curve like a brick wall until you get going (at least for me), then its a downhill ride. I've been thinking about getting the Raisonance interface with RIDE, but I may spend a few days getting eclipse set up first.

Once I get set up and back in the groove, I'd be glad to help out with the programming.


----
[www.binaryconstruct.com]
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 14, 2009 05:18AM
I got a stepper motor going with my board last night !

Only problem, is I thought I would try to finesse the steps a little, and go from coil 1 to coil 1+2 to coil 2 to coil 2+1 to coil 1 etc.

I assumed the complier could handle a right shifting a 32 bit value an arbitary number of bits, especially since the chip has a built in barrel shifter.

However, it gets confused, even if I try only 4 steps by doing double steps (two each of the same value)

I think there must be some ARM specific compiler functions that I can uses, but I can't figure where the documents are describing them.eye rolling smiley

Graham.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 14, 2009 05:50AM
You will need the value to be unsigned otherwise it may sign extend when shifting right.


[www.hydraraptor.blogspot.com]
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 15, 2009 04:11AM
Hi nophead,

I'm using u32 values, where I'm assuming the u means unsigned.

/*port, position in table, least sig bit of nibble to change.*/

/*invocation: SteppinOut(GPIO? ,tableindex 0 to 7, offset); */

void SteppinOut(GPIO_TypeDef* GPIOx, u8 pos, u8 LScool smiley

{

u32 temp;

u32 temp2;

temp = (0x15462A89 >> (pos * 4)) & 0x0000000F;

temp2 = temp ^ 0xF;

temp = temp << LSB;

temp2 = temp2 << LSB;

GPIOx->BSRR = temp;

GPIOx->BRR = temp2;

}

In case it's not clear, I make a periodic call like this:
StepCount=0;
while(1)
{
//Testing 4 x stepper motors:
SteppinOut(GPIOD,StepCount,0x0);
SteppinOut(GPIOD,StepCount,0x4);
SteppinOut(GPIOD,StepCount,0x8);
SteppinOut(GPIOC,StepCount,0xA); // (this motor not nibble aligned drive)
Delay(0x900);
StepCount++;
if (StepCount>7)StepCount=0;
}
(there's other stuff too, this is edited for clarity)

I know it's very far from being compact code, but at the moment, I'm more concerned with spreading things out to identify errors, as I don't have much confidence in programming in C so far.
Theoretically, the BSRR register is 32 bits in the chip user manual, but in the Raisonance code, they are using BSRR to refer to the low 16 bits, and BRR to refer to the high bits.

I may yet convert this code to a lookup table for practicality, but it seemed to me to be more efficient to simply load a 32 bit stepper table of 8 nibbles, barrel shift it right 4 x the position in the table, 'and' it with 0xF, and then write that value to the port position to set bits, 'and' it's xor value to the upper bits to clear as required.

The code works if I use the even values to 16 bits, or the odd values to 16 bits, but not if I double them up, or intersperse them in the single/double/single/double.. drive mode. (I do change the pos loop from 0-3 with 16 bits, to 0-7 on 32)

I have PWM control available for each channel, so I suppose, ultimately it's not an issue, however it's bugging me at the moment, as I know how do do this sort of thing easily with assembly.

Otherwise, all 4 axis of stepper motor function, except for stepper motor #2, and that's due to pin PC-13 booting up as a default something or other else, it's segregated seperatly from pins PC10-12
I'll figure that one out in due course...

Edited 1 time(s). Last edit at 05/15/2009 04:17AM by grael.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 15, 2009 04:53AM
Curiously,
I tried again on the 32 bit 8-nibble look up table, and it works now eye rolling smiley

All I can conclude, is that (I had a select case type statement,) and I may have previously unbalanced it with a delay external to the case selection body.

It's running now anyway, and it's smoother, I can get about 25% more speed by interspersing single and dual coil drive. smiling smiley
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 18, 2009 06:34AM
I'm stuck at the moment,
[www.st.com]
The libraries and the chip documents don't quite seem to match, so I'm waiting on a reply from STM. Either I've overlooked something obvious, or there's a lot more work involved in using the libraries than one would expect, in which case it's almost worth discarding some and starting afresh.

STM make their chips with extraordinarily flexible I/O though, so it's a lot of work in the latter case. sad smiley
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 21, 2009 04:41AM
Sometimes it's productive to leave a problem for a day or two, and come back to it fresher.

I had another crack at PWM last night, on the steppers instead of my piezo this time. I set only half the stepper motors to PWM (GPIO_Full_Remap_TIM3) etc, and after some messing around, I got some motion on a stepper again (jerky this time), and then sped up the timer to smooth the control.

Tonight's challenge is simple: the PWM is symetrical=50/50 on/off time so far, I need to find the CMSIS routines to load the correct registers with arbitary values, and vary the on/off time smoothly between 0 and 100%. Also, I need to check that I have the channels allocated correctly to each stepper motor coil control, there are, I think 17 channels available for PWM output, and I need 8 for the steppers, and any other free ones I will enable as required for servo, LED, piezo control. All this could be done purely in software on a fast micro like the ARM, but I'm automating aspects of it to improve accuracy and free ARM time for other tasks.

The other manufacturer's arm cortex M3 chips are nice too, but this one has amazing hardware flexibility that I'm happily using winking smiley

Edit:
Getting late, but I've now had the PWM working for the last hour or so.
I have three motors hooked up for testing, and the smaller ones with less turns seem to be less amenable to drive at high frequency PWM, as I vary the base frequency of the PWM, Different motors seem to loose torque, as resonant effects upset the work output. (I think this is what is happening) It's fantastic to be able to finally throttle the motors.

I'll have to get the LCD up and running soon, and then the ADC, and the keypad. Those sorts of things really speed up development cycles. smiling smiley

Graham.

Edited 1 time(s). Last edit at 05/21/2009 08:06AM by grael.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 25, 2009 05:10AM
Those who have been following this thread, may have noticed that I'm a C newbie.

This weekend, I experienced some frustration with trying to modulate the drive power, and to change direction of the stepper motors while they were running (like a washing machine action). My software wasn't working as expected angry smiley Finally, I tracked it down to having assumed that parameter n1 and parameter n2 and parameter n3 etc(for example) being linked as n1 | n2 | n3, having assumed that "|" meant a bitwise logical and.

no, no, no!

Eventually I double checked, and immediately realised, on seeing the definition for "|" as being a bitwise or, what I had done, and why my code wasn't working. yawning smiley

No surprises..."&" is the bitwise and symbol.eye rolling smiley

So, I tidied up, and got some funky motion running on my stepper motors.


The next challenge has had me stumped for the rest of the weekend though.
Using the interrupts...

In a small 8 bit microcontroller project, the files are smaller, and fewer. Interrupts are usually set up as a vector table, and the address placed within the table is where the chip goes to when that interrupt condition occurs. You manually edit the vector table with the names of the routines you want to process the information, and the compiler replaces the names with the name's address locations.

The number of include files (*.C and *.H) are legion with the STM32 however. sad smiley I can add them into my project for direct viewing, but when I try to assemble, the compiler gets confused, and complains about errors, if I include all the files.

There is a huge amount of functionality for interrupts, but the single problem I have, is trying to find the vector table relationship to the actual code I need to run in that interrupt.

I left a query on the STM32 forum last night, but no reply from anyone yet.

Each thing like this I resolve gets me another step closer to a working maching, but it's very frustrating at the moment.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 25, 2009 06:11AM
you should only be including the .H files.

.H files tell the compiler what the interfaces are. (what)
.C files contain the actual code. (how)

you should only need any .H files for functions you use in your code, e.g. if you use the timer2_interrupt() function, you need to include the .h file that mentions that funtion. ignore the .C files.

of course, I might be way off base. Try posting a code snippet or the compiler error, too - it might help explain what's been going on.


---
Reprapping blog and other rants: [renoirsrants.blogspot.com]
My Reprap: [sites.google.com]
Greetings all,

I'm finally on the scoreboard in the Cortex game, albeit just barely. I had been unable to get my little STM32 Cortex board [www.futurlec.com] to talk at all (wasn't being recognized by the STM flash loader utility.) I found my error (a loose solder joint on a voltage regulator), and now it talks.

To set up the toolchain and program a blinking LED,
I adapted the instructions from
[wiki.fosstronics.com]

More details are in my build blog.

-- Larry


Larry Pfeffer,

My blog about building repstrap Cerberus:
[repstrap-cerberus.blogspot.com]
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 26, 2009 03:24AM
Larry,
Great to see you have some progress too ! smiling smiley
I see the protoboard is fairly bare bones, which is good, you don't have to deal with stuff going to connections you don't want in your application.

Have a good long look at the I/O, a lot of it can be remapped, and you can even run timers as encoder counters. I spent a big part of my circuit board design on mapping pins. Somewhere, I saw something about being able to do 6 PWM with the advanced timer, this might be useful to you if you can track it down.

Generally, you can take any one of the main timers TMR1-TMR4, set up input clock source, divider, and an integer prescaler, and then string compare counts for up to 4 channels off each main counter.


Easy to do the same for servos.



DaveR,
In the library files I'm using, the C files have the include lines to reference the H files of the same prefix.

I have a suspicion that I'm meant to make my own ISRs, and then pass the name of each one to the STM firmware to use as ISR addresses in the ISR vector table, but this aspect of the documents lacks clarity. It's what I would do if I was trying to set up for a similiar situation and knew how to, but I'm still coming to grips with C.

One of the STM developers mentioned always having a copy of the STM firmware giude open, and after I found it again, I think that's going to be my policy too, at least initially. The guide is over 500 pages long, I can find interrupt setup information, all but this specific information. I don't want to hack the firmware files, causes too much anguish when dealing with code porting to later chips by same manufacturer.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 26, 2009 07:15AM
Very curious,
No where in my files have I been able to locate an inclusion reference to stm32f10x_it.c, and yet when I add one into my project directory, it becomes active, despite not causeing errors when previously absent.

I booted up the SysTick interrupt, pus some simple code between the curlies { } after the SysTick handler label, and it works. eye rolling smiley

I would prefer to know how it attaches to the rest of the firmware library, but nobody on the STM32 forums either knows, or is willing to say sad smiley However, it works, so I can get on with shifting my servo test stuff to being sys tick triggered, and I can start implementing other important things like communications and servo PWM wave form generation.

Onwards ! hot smiley
Hi Grael,

With reference to finding the vector table...
Are you using the RIDE IDE? Go to Project, Properties. LD Linker, Startup. Does it say use the default startup? And it is "$(RkitInst)lib\ARM\crt0_STM32x.o"?

This is the precompiled version of the "crt0_STM32x.c" file. Although your project is not explicitly saying 'use this C file' it is doing so in effect.

I hope this helps - I had the same nagging curiosity.

Regards, Nick.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 28, 2009 03:09AM
Thanks Nick, yes, I have that setting here too.

It's a bit different from assembler, when you specify EVERYTHING, and you have your finger on the pulse of everything too...

I am enjoying learning C though. Apart from the irritations...
Like at the moment, I'd really like to know how to chose scope of variables, and I can't figure out the correct syntax yet, I don't want my interrupts to be doing lots of call stacking, I want to share a few variables between files, but Haven't figured out how yet. moody smiley
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 28, 2009 04:16AM
If you want a variable to have file scope you define it outside a function with the keyword static. E.g.
static int a; // a is local to this file

void v(void) {
  ++a;
}

If you want global scope you omit the static keyword. E.g.

int a;     // a is a global variable

void v(void) {
  ++a;
}

To access it from another file use extern. E.g.
extern int a;

Generally you put the extern declaration in a header file and include it where the variable is defined and where it is used. That way it ensures you define it as the same type everywhere.

If a variable is modified by more than one thread, e.g. in an interrupt then you need to declare it volatile. E.g.

volatile int a;

Otherwise the compiler will generate code assuming that the variable does not change in between writes.


[www.hydraraptor.blogspot.com]
Hi Grael,

I know what you mean about using assembler and moving to C. When you're using a micro as an electronic component you have it fit in with all the other components and you know what it's doing down to the microamp/clock cycle.
You know where every variable is in RAM because you told the assembler where you wanted it.

I gave up learning assembler for new micros about 3 years ago when I had to use the MSP430 in work. I've used that micro in about ten designs now and don't know anything about the micro's instruction set other than 'it's orthogonal' and 'highly optimised for C'!

After you've read a standard C text book everything else is compiler-specific (like the start-up config issue we both had). And also MCU-specific, like how the peripherals function. But at least you don't have to learn the op-codes, which gets too much for me when the micro supports more than one addressing mode! smiling smiley

Sometimes you have to sit back and let the vendor libraries take the strain because there would otherwise be too much work for one man to do.

However, an inquisitive mind will bog you down in the detail...

I don't know. Maybe one has to compromise on the amount we actually know about the products we make if we are to make anything of any complexity.

smiling smiley Nick.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 29, 2009 04:44AM
Thanks nophead !

I figured out the extern command yesterday, and started using it, but had some strange side effects using a variable in and out of interrupts, and wondered if there was an issue with the interrupt fiddling at the wrong time, the "volatile" command explains what I was missing !

I was using a u16 [5] variable for the step selections, and two motors wouldn't count, changed it to u32, and they did. Probably to do with needing to be volatile.


After I sorted the extern command last night, I was running everything at top speed, and wasn't too impressed with the speed of my C code implementation.

So, this weekend I will change to precalculated stepper drive signals rather than figuring them out on the fly. If I don't do this, I'll have really horrible granularity at the upper speeds.

I'm wanting to string lots of things off the SYS tick interrupt, but with a state machine, so each task gets it's shot, in a specific time frame, but without congesting the processor too much at any specific slot.


Nick, I know what you mean. Variable allotment, string handling, jump tables, working with parameter passing and trying to make it flexible in assembler, can be tiresome. I used a lot of macros, to speed up the most used things that needed in line speed. The AVR are really easy to write assembler for. If I'd grown with the ARM chip, I would have probably used assembler for it too, but I will see how my code speed is after some optimisation.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 29, 2009 05:27AM
I am surprised you have speed issues in C on such a powerful processor. You should be able to compute phase patterns several orders of magnitude faster than they need to be output and C should not be significantly slower than assembler on a CPU with a reasonable instrcution set (i.e. not PIC).

Edited 1 time(s). Last edit at 05/29/2009 05:28AM by nophead.


[www.hydraraptor.blogspot.com]
If you're using the SysTick to schedule lots of different tasks might I recommend FreeRTOS? It took me a week to learn about what an RTOS actually is and to be able to write a multitasking application using it. It’s basically about 4k of code that sits on the SysTick and can be used in your ‘tasks’ and ISRs.

This is what my app does (it was written for the STM32 Primer1):

1. Flashes a red LED at one rate.
2. Flashes a green LED at another rate.
3. Makes a sound through a piezo.
4. Reads position information from a MEMS device.
5. Moves a pointer across an LCD screen.
6. Waits for the push button to be pressed then outputs the pointer position on the LCD.

FreeRTOS basically does what you’re trying to implement. The website has lots of good tutorials and ports (translations) for different micros and development boards.

To me it was time well spent because there is no way I’d have been able to write scheduling code that efficiently.

Cheers, Nick.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 29, 2009 08:07AM
Nophead,
I shortened it to running 4 switch case statements, each with 4 options.

If I knew C better, I'd try to to a 32 bit load of the BRR and BSRR registers concatenated(they are two parts of a 32 bit register), but instead I'm using the
GPIO_WriteBit routines. If I shorten it like the fowlowing code, it almost chokes on a systick reload of 0x100, or 256 dec.


void SysTickHandler(void)

{

//if (ledtogglestate==0) {GPIO_WriteBit(GPIOB,GPIO_Pin_11,Bit_SET); ledtogglestate=1;}

//else {GPIO_WriteBit(GPIOB,GPIO_Pin_11,Bit_RESET); ledtogglestate=0;} // piezo



GPIO_ResetBits(GPIOC, 0b11110000000000);

switch (MotorPhase[2]&3) //motor #2

{

case 0:

GPIO_SetBits(GPIOC, 0b01010000000000);

break;

case 1:

GPIO_SetBits(GPIOC, 0b01100000000000);

break;

case 2:

GPIO_SetBits(GPIOC, 0b10100000000000);

break;

case 3:

GPIO_SetBits(GPIOC, 0b10010000000000);

break;

}



GPIO_ResetBits(GPIOD, 0b111111111111);

switch (MotorPhase[1]&3) //motor #1

{ //56a9

case 0:

GPIO_SetBits(GPIOD, 0b01010000);

break;

case 1:

GPIO_SetBits(GPIOD, 0b01100000);

break;

case 2:

GPIO_SetBits(GPIOD, 0b10100000);

break;

case 3:

GPIO_SetBits(GPIOD, 0b10010000);

break;

}

switch (MotorPhase[3]&3) //motor #3

{

case 0:

GPIO_SetBits(GPIOD, 0b010100000000);

break;

case 1:

GPIO_SetBits(GPIOD, 0b011000000000);

break;

case 2:

GPIO_SetBits(GPIOD, 0b101000000000);

break;

case 3:

GPIO_SetBits(GPIOD, 0b100100000000);

break;

}

switch (MotorPhase[4]&3) //motor #4

{

case 0:

GPIO_SetBits(GPIOD, 0b0101);

break;

case 1:

GPIO_SetBits(GPIOD, 0b0110);

break;

case 2:

GPIO_SetBits(GPIOD, 0b1010);

break;

case 3:

GPIO_SetBits(GPIOD, 0b1001);

break;

}


The motors run OK, off a properly set up HCLK source driven SysTick, but if I take the reload value much below 0x200, then the interrupt routine swallows it's own tail, and freezes operation.

I know I could ultimately transfer a good portion of this into RAM for faster operation, but I'm taking simple steps for now.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 31, 2009 05:00PM
You will find this more code size and runtime friendly:
void SysTickHandler(void)
{
	//if (ledtogglestate==0) {GPIO_WriteBit(GPIOB,GPIO_Pin_11,Bit_SET); ledtogglestate=1;}
	//else {GPIO_WriteBit(GPIOB,GPIO_Pin_11,Bit_RESET); ledtogglestate=0;} // piezo

	U16 Motor1Phase = 0;
	U16 Motor2Phase = 0;
	U16 Motor3Phase = 0;
	U16 Motor4Phase = 0;

	GPIO_ResetBits(GPIOC, 0b11110000000000);
	GPIO_ResetBits(GPIOD, 0b111111111111);

	switch (MotorPhase[1]&3) //motor #1
	{ //56a9
		case 0:
			Motor1Phase = PHASE0;
		break;
	
		case 1:
			Motor1Phase = PHASE1;
		break;
	
		case 2:
			Motor1Phase = PHASE2;
		break;
	
		case 3:
			Motor1Phase = PHASE3;
		break;
	}

	switch (MotorPhase[2]&3) //motor #2
	{
		case 0:
			Motor2Phase = PHASE0;
		break;

		case 1:
			Motor2Phase = PHASE1;
		break;

		case 2:
			Motor2Phase = PHASE2;
		break;

		case 3:
			Motor2Phase = PHASE3;
		break;
	}
	
	
	switch (MotorPhase[3]&3) //motor #3
	{
		case 0:
			Motor3Phase = PHASE0;
		break;
	
		case 1:
			Motor3Phase = PHASE1;
		break;
	
		case 2:
			Motor3Phase = PHASE2;
		break;
	
		case 3:
			Motor3Phase = PHASE3;
		break;
	}

	switch (MotorPhase[4]&3) //motor #4
	{
		case 0:
			Motor4Phase = PHASE0;
		break;
	
		case 1:
			Motor4Phase = PHASE1;
		break;
	
		case 2:
			Motor4Phase = PHASE2;
		break;
	
		case 3:
			Motor4Phase = PHASE3;
		break;
	}
	
	GPIO_SetBits(GPIOC, (Motor2Phase << 8));
	GPIO_SetBits(GPIOD, ((Motor1Phase << 8) | (Motor3Phase << 4) | Motor4Phase));
}

Edited 1 time(s). Last edit at 06/02/2009 08:53AM by annodomini2.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
May 31, 2009 07:01PM
thanks annodomini2,

That certainly reduces the number of calls made within the interrupt, although I'm not sure there's a savings on portC, which still would only make one of the 4 possible phase settings.

I had a look at my list code before, and it did seem to compile to something a bit unwieldy.

I couldn't see any evidence of the switch case statement utilising a jump table, so I'm guessing it simply threads through the case-option-break statements, only dropping the false options. Very wasteful of C, ant the microcontroller's time on such a time critical task.

That raises the question of whether it's actually preferable to build an if...then table, branching for each decision, for linear numerically coded jump options.


something like this:

if (phase & 2)==2
{
if (phase & 1)==1
action(3);
else
action(2);
}
else
{
if (phase & 1)==1
action(1);
else
action(0);
}

}

Which could be expanded out a lot further if required, and is unwieldy, but ought to be faster than a switch case for a simple number series, especially if it's a power of 2 series.


Once you get into a table size of 8, 16, or bigger, there ought to be significant time savings, as you jump through the bit positions, rather than each number.

But I think I'd need to learn how to code a real jump vector table in C in that instance !



I see with your changes, it would be practical to shift the :
GPIO_ResetBits(GPIOC, 0b11110000000000);
GPIO_ResetBits(GPIOD, 0b111111111111);
lines to just above:
GPIO_SetBits(GPIOC, (Motor2Phase << 8));
GPIO_SetBits(GPIOD, ((Motor1Phase << 8) | (Motor3Phase << 4) | Motor4Phase));

That way there's minimal off period discrepancies between motors.

Edited 2 time(s). Last edit at 05/31/2009 10:42PM by grael.
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
June 01, 2009 08:26AM
Depends on the compiler and how many conditionals to if it will use a jump table.

IMHO, I would build the bit allocations in the function where you declare the motor phases and remove the calculation from the interrupt completely, you want as little in there as possible.

I would suggest using an enumeration with the Bit patterns set to the value such as I did with the define statements, makes the code a little easier to read.

And put the bit patterns in global memory and just call the reset and set functions in the interrupt.

Don't forget to declare the global variables volatile.
Global volatile poor choice for use in ISR
June 01, 2009 10:13AM
Greetings all,

I agree that pre-computing the bit patterns is a good idea, esp. for use in an ISR. However, if they are pre-computable, you'd do much better to make them const (const enums is fine) or #defines. Then the compiler can use the fastest (of many) ways to get that bit pattern into a register in the ISR.

Declaring these patterns to be global volatile *forces* the compiler to (re-)read them from RAM -- and that may well be slower than loading a constant from the (probably already fetched) next word or two in the instruction stream. Giving the compiler some options here can generate (surprizingly) clever code.


Larry Pfeffer,

My blog about building repstrap Cerberus:
[repstrap-cerberus.blogspot.com]
Re: Global volatile poor choice for use in ISR
June 01, 2009 11:47AM
Larry_Pfeffer Wrote:
-------------------------------------------------------
> Greetings all,
>
> I agree that pre-computing the bit patterns is a
> good idea, esp. for use in an ISR. However, if
> they are pre-computable, you'd do much better to
> make them const (const enums is fine) or #defines.
> Then the compiler can use the fastest (of many)
> ways to get that bit pattern into a register in
> the ISR.
>
> Declaring these patterns to be global volatile
> *forces* the compiler to (re-)read them from RAM
> -- and that may well be slower than loading a
> constant from the (probably already fetched) next
> word or two in the instruction stream. Giving the
> compiler some options here can generate
> (surprizingly) clever code.


Actually it should be quicker in this instance, currently there is a need to read 4 parameters from RAM, this would be reduced to 2.

the defines allow the data to exist in flash, but you still need variables to pass the information into the function.

As the parameters are not modified there may not be a need for volatile, but be prudent as if the situation changes in the future and the function does modify the parameters it can cause a whole host of issues, which become a nightmare to debug.

For the sake of peace of mind and a few clock cycles, I personally would go with volatile, IMHO its good practice.
Global volatile poor choice for use in ISR
June 01, 2009 01:00PM
Greetings all,

I agree that pre-computing the bit patterns is a good idea, esp. for use in an ISR. However, if they are pre-computable, you'd do much better to make them const (const enums is fine) or #defines. Then the compiler can use the fastest (of many) ways to get that bit pattern into a register in the ISR.

Declaring these patterns to be global volatile *forces* the compiler to (re-)read them from RAM -- and that may well be slower than loading a constant from the (probably already fetched) next word or two in the instruction stream. Giving the compiler some options here can generate (surprizingly) clever code.


Larry Pfeffer,

My blog about building repstrap Cerberus:
[repstrap-cerberus.blogspot.com]
Re: Software phase, ARM Cortex_M3 STM32 based highly integrated control board.
June 02, 2009 03:12AM
I see there's been some activity while I slept, and went to work !

My main effort over the weekend went to shifting as much calculation into the interrupt as possible, removing case statements, and if..else statements, converting them all to boolean and linear maths.

ST7 user (company rep?) on STM32 forums put me right on "extern", and sharing of variables across multiple files.


I did quite a bit of recoding over the weekend, but theres a bit that's unreliable on my motor PWM setting call, which I've been updating from within my interrupt. I can comment it out there, and it's still dodgy in the main.c program for some reason. I also fell into the trap of adding temp=v1+v2+v3-(v4+v5+v6), took me a while to track some erroneous operation to a lack of brackets around the first 3 variables (representational of my actual code)

For some reason, shifting the vast majority of the motor control code into interrupt seemed to make my program run a lot faster, along with the obvious consequence of removing unsynchronised granularity between updates and actions.

Currently, I can set 4 absolute positions, and have the motors run to and stop at those positions, but there's a lot of finessing to do. I need to solve the PWM unreliability issue (might shift all that code to interrupt), and I want to get working my implementation of the half stepping that was mentioned over in another thread. Basically, I currently use an extra bit of resolution in my position variables, and look for a 00 or a 11 in that last two bit fields. if either test is true, that sets a variable which I use as an index to fetch either a PWM[0] or PWM[1] value, one being 100%, and the other yet to be determined. If I run the PWM much under 40%, the power diminishes drastically. 50% give reasonable idle holding torque, but without overheating motors or L298s

I think my next step, is to solder on an LCD, and write some code for it. Nothing quite beats the simplicity of sending questionable variable contents to an LCD for inspection !

Also, now my interrupt seems to be running blazingly fast, and the motors are able to be controlled at the upper limit for full step mode/2 with systick=5000, I can look at putting in some "skip n steps, update" sequencing from the interrupt, which will allow for some external monitoring and adjustment of relative channel speeds (necessary for doing any complex moves smoothly.)

To throttle current down when the absolute set positions are achieved, I used a barrel shift right of the chosen PWM value by the truth value of (chosenAxis.required==chosenAxis.actual), so that on reaching it's destination, the channels power is halved. This was so I could maintain the highpower half stepping positions at diminished power. Also, calculating like this allowed me to skip messy test statments.

However, I'm not sure C is letting me actually do the barrel shift via a variable , and I don't know if I'm missing a special syntax. Here's some of my code:

-----------------------------------------------------------------------------

void SysTickHandler(void)
{
//only one channel shown:
s32 temp;
u8 stopW;

temp=(w.req-w.actual);
w.actual+=((temp>0))-((temp<0));//simple + or - stepping based on difference
stopW=(temp==0); //stopW set to 1 on equality of set versus actual positions

MotorSteplock(1,(w.actual&6)>>1);// next stepper position, drop dither bit.

temp=(((w.actual&2)==0) | ((w.actual&2)==3));//new temp value=1 if 00 or 11
PWMStepperMotorCoilPair(1,wPWM.phase[temp]>>(stopW),wPWM.phase[!temp]>>(stopW));

// ch, dither["1=full on 11 or 00, 0=partial PWM otherwise"], other dither


//calls within main.c:

void MotorSteplock(u16 S_motor,u16 pos)
{
switch(S_motor)
{
case 1:
SteppinOut(GPIOD,pos,0x4);
break;
case 2:
SteppinOut(GPIOC,pos,0xA);
break;
case 3:
SteppinOut(GPIOD,pos,0x8);
break;
case 4:
SteppinOut(GPIOD,pos,0x0);
break;
}
}


void PWMStepperMotorCoilPair(u16 S_motor,u16 percentA,u16 percentB )
{
switch(S_motor)
{
case 1: // Stepper motor #1
TIM_SetCompare1(TIM4,percentA);
TIM_SetCompare2(TIM4,percentB );
break;
case 2: // Stepper motor #2
TIM_SetCompare3(TIM4,percentA);
TIM_SetCompare4(TIM4,percentB );
break;
case 3: // Stepper motor #3
TIM_SetCompare1(TIM3,percentA);
TIM_SetCompare2(TIM3,percentB );
break;
case 4: // Stepper motor #4
TIM_SetCompare3(TIM3,percentA);
TIM_SetCompare4(TIM3,percentB );
break;
}
}



void SteppinOut(GPIO_TypeDef* GPIOx, u16 pos, u16 LScool smiley
{
u32 temp;

temp = (0x56A9 >> (pos * 4)) & 0xF;
GPIOx->BSR = (temp ^ 0xF) >> LSB;
GPIOx->BSRR = temp << LSB;

}

Edited 2 time(s). Last edit at 06/02/2009 03:34AM by grael.
Sorry, only registered users may post in this forum.

Click here to login