need some hints and props
Hello
I have QuickStart board, and finally got some time to play with it...
I never programmed in C/C++, but i have experience in Java, Pascal, PHP, Perl, (*)sh, JavaScript...
I will post my code here (this "my code" take with reserve, because i took one or two functions from this forum and changed them to suit my needs), and if anyone can give me some comments about it and how something can be done better/faster, I would be most grateful!
Also, what it best way of signalling to a thread? here i'm using global variable, but i don't like it!
Thx
also, does pausems function pauses for given nanoseconds or I miscalculate it completely??
edit: i forgot to say, this code is for driving Nema17 stepper motor with L298N driver board...
I have QuickStart board, and finally got some time to play with it...
I never programmed in C/C++, but i have experience in Java, Pascal, PHP, Perl, (*)sh, JavaScript...
I will post my code here (this "my code" take with reserve, because i took one or two functions from this forum and changed them to suit my needs), and if anyone can give me some comments about it and how something can be done better/faster, I would be most grateful!
Also, what it best way of signalling to a thread? here i'm using global variable, but i don't like it!
Thx
#include <propeller.h> #include <sys/thread.h> static int pin[] = { 12, 13, 14, 15 }; #define STACK_SIZE 64 static int cog_stack[STACK_SIZE][1]; static _thread_state_t thread_data; signed int direction; int stepType = 2; // 2 -> halfStep, 1 -> fullStep int stepArray[] = {1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1}; void setPinState(int pin, int state) { unsigned int mask = 1 << pin; DIRA |= mask; switch (state) { case 0 : OUTA &= ~mask; //pin set to low break; case 1 : OUTA |= mask; //pin set to high break; } } void pausems(long int given) { if (given > 0) waitcnt(CNT + (CLKFREQ/1000000) * given); // Wait "given" nano(?)seconds } void setState(int p1, int p2, int p3, int p4, long int delay) { setPinState(pin[0], p1); setPinState(pin[1], p2); setPinState(pin[2], p3); setPinState(pin[3], p4); pausems(delay); } void singleHalfStep(int dir) //this and next function are new, and still not finished. they need to have ability to change direction.. { setState(stepArray[ 0+0],stepArray[ 0+1],stepArray[ 0+2],stepArray[ 0+3], 400); setState(stepArray[ 4+0],stepArray[ 4+1],stepArray[ 4+2],stepArray[ 4+3], 400); setState(stepArray[ 8+0],stepArray[ 8+1],stepArray[ 8+2],stepArray[ 8+3], 400); setState(stepArray[12+0],stepArray[12+1],stepArray[12+2],stepArray[12+3], 400); setState(stepArray[16+0],stepArray[16+1],stepArray[16+2],stepArray[16+3], 400); setState(stepArray[20+0],stepArray[20+1],stepArray[20+2],stepArray[20+3], 400); setState(stepArray[24+0],stepArray[24+1],stepArray[24+2],stepArray[24+3], 400); setState(stepArray[28+0],stepArray[28+1],stepArray[28+2],stepArray[28+3], 400); } void singleFullStep(int dir) { setState(stepArray[ 0+0],stepArray[ 0+1],stepArray[ 0+2],stepArray[ 0+3], 400); setState(stepArray[ 8+0],stepArray[ 8+1],stepArray[ 8+2],stepArray[ 8+3], 400); setState(stepArray[16+0],stepArray[16+1],stepArray[16+2],stepArray[16+3], 400); setState(stepArray[24+0],stepArray[24+1],stepArray[24+2],stepArray[24+3], 400); } void rotate() { int stepArray[32]; while (1) { if (direction == 1) for (int i = 0; i < 4 * stepType; i++) { setState(stepArray[i*4+0],stepArray[i*4+1],stepArray[i*4+2],stepArray[i*4+3], 800 / stepType); } else if (direction == -1) for (int i = (4 * stepType) - 1; i > -1; i--) { setState(stepArray[i*4+0],stepArray[i*4+1],stepArray[i*4+2],stepArray[i*4+3], 800 / stepType); } else setState(0, 0, 0, 0, 0); } } int main (int argc, char* argv[]) { direction = 0; int cog = _start_cog_thread(cog_stack[0] + STACK_SIZE, rotate, 0, &thread_data); direction = 0; // these few lines are for testing... pausems(1000000); direction = 1; //rotate in one way pausems(1000000); direction = 0; //stop rotation pausems(1000000); direction = -1; //rotate other way pausems(1000000); stepType = 1; direction = 1; pausems(1000000); stepType = 2; direction = 1; while(1) { } return 0; }
also, does pausems function pauses for given nanoseconds or I miscalculate it completely??
edit: i forgot to say, this code is for driving Nema17 stepper motor with L298N driver board...
Comments
The global variable as you have it does work too, but it's a bit cleaner to isolate everything in the structure.
Eric
A slightly more general function to use is usleep(n) (which is in the C library, and also takes microseconds). It will work correctly even if you end up using pthreads to run the thread on the same COG as the main code, whereas pausems literally pauses the COG and prevents other threads from running on it.
Eric
i did your modifications, in function "rotate" and in "main"
but now i got this warnings when i compile it...
and it doesn't work anymore?
edit: it works, I had one small error in code... but, warnings are still there...
thx...
p.s. probably i'm missing something, but i don't know what... thx again...
You can fix that by moving the "volatile" into the definition of the structure: and removing the "volatile" from the definitions of struct mbox mailbox and rotate.
The effect should still be the same -- the earlier version declared the entire mailbox structure to be volatile, this version declares just the "direction" field to be volatile and subject to change by other threads, but since that's the only field of the structure the generated code will end up the same.
Eric
@ersmith: i changed struct and removed volatile from function parameters, and i got rid of one warning message... but still i have this one:
it seems that compiles doesn't like '&message' variable in _start_cog_thread function...
is it safe to ignore it?
and another question to anyone willing to help... can following section be written better?
by better I mean with less data and code? and i still need to figure out how to reverse statements in sigleHalfStep function regarding 'dir' variable value.
and would there be any speed improvements if i write functions for sending impulses to driver in assembler? or that would be too complicated compared to (possible) gain?
thx
Yes, it is safe to ignore it. void * is compatible with all pointers. If you want to get rid of the warning you can declare repeat as something like:
How about something like:
The compiler will decide if it's better to unroll the loops or not -- you can optimize for space with -Os and for speed with -O3.
It's unlikely that there would be many speed improvements. Are you finding that speed is an issue? Premature optimization is usually a bad idea -- if it ain't broke, don't fix it!
Oh, and the other thing you may want to look at is how sensitive your loop is to timing. If you really need exact microsecond delays, the best bet is probably to use __builtin_propeller_waitcnt and keep track of the current cycle counter across calls to setState. usleep() and the pauseMs() function you were using earlier will both wait for N milliseconds, but that doesn't count the time spent in overhead and the time spent actually doing the step. If you want the impulses to actually arrive at exact intervals you have to take that time into account. For most applications it probably doesn't matter, but I thought I would mention it in case you do have timing requirements.
Eric
and why have you put inline in front "void setPinState"? thx
speed is not an issue, but this is my first venture to microcontrollers, so I'm total newbie in this field. Also, if I put less than 330 ms in delay, stepper motor starts to vibrate but no spinning, so I'm not sure is it because of QuickStart board (some racing conditions in pins?) or maybe driver board...
and timings in this part are not important.... because i'll use number of steps for rotation (in my case, 400 half steps for one revolution), not time of rotation...
when i come home, i'll try these changes...
thx
btw., it turns out that i have another driver board at home! :-D
Other things to improve the code:
(1) The "switch" statement in setPinState is slightly inefficient, because there are actually three cases generated by the compiler: pin == 0, pin == 1, and pin == anything else (for which the switch does nothing).
(2) There's no need to use up a whole "int" (32 bits) to hold the stepArray values. "char" (8 bits) would save some data space. Or, you could compress the pin states, for example putting 4 in each char by manipulating the bits, although that gets a bit more complicated (unless the pins are contiguous, see below)
(3) If the pins are all together you could easily store the 4 bits together and set all of them at once via something like: