Not simple BLDC controller It RUNS! :)

My goodness Arlo, use a socket on that poor IC. I am surprised you haven't cook it? I have a couple of breadboards like in Lebowski's pictures and some sockets you can have.
 
Gordo said:
My goodness Arlo, use a socket on that poor IC. I am surprised you haven't cook it? I have a couple of breadboards like in Lebowski's pictures and some sockets you can have.
Yup surface mount! I will look at making the next version cleaner but this is the way it is for now!
 
OK guys. I'm just starting to get this C programing thing.... I do have a long road ahead of me but I am not giving up I have wanted to be able to use microchips for this kid of thing for a long time.
So my questions go like this.
#1 Is there a simple list for microchip of the C code? Or what files do I look for in my computer. List specific to dspic30f3010?
#2 How do I get a throttle to flash the LED at different speeds?
#3 How do I work on the rs232? I have spent over 40hours on my computer learning this and I'm not afraid to spend 1000s of hours more but every few days I want to see some progress.
I'm not asking to be spoon fed info but its just so hard to find what I want and everything is so u n organized!
 
I found some of my info in the H file but its not labled well in my free C30 compliler... I also looked in the ? tab but its not to helpfull lol. My head hurts. :lol:
 
Arlo1 said:
#1 Is there a simple list for microchip of the C code? Or what files do I look for in my computer. List specific to dspic30f3010?
#2 How do I get a throttle to flash the LED at different speeds?
#3 How do I work on the rs232? I have spent over 40hours on my computer earning this and I'm not afraid to spend 1000s of hours more but every few days I want to see some progress.
I'm not asking to be spoon fed info but its just so hard to find what I want and everything is so u n organized!

#1: what do you mean by 'simple list' ? For assembler there's a list of instruction but I never heard of this for C.
#2: this is a whole program !
#3: for this you just need to write the correct values to the correct registers. Have a look at the assembler subroutines I posted a few
pages earlier. They're in assembler but you should be able to deduct from them which values get written into which registers. Also have
a look at the general 30F manual (link posted a few pages back) at the UART (RS232) section. There you can find what the values
written to the registers actually mean.
 
If you are new to the C programming language go pick up a book like C for dummies or similar. Its the same regardless if to code for a dsPIC or a banking system or whatever. You can download a C compiler for your PC and try out some examples in the book to get a feel for it. Then you can get into the specifics of coding for the PIC.

There is nothing wrong with spoon feeding, I do it for a living, ie building software platforms that handles all the itty gritty and nasty details of the hardware for the application engineers. :)
 
About #2. In brief you first need to connect the pot to one of the AD inputs and ensure that it varies to voltage from 0 to 5 volts (or whatever your Vcc is). Then you have to set up the AD hardware inside the chip to use the pin as an AD (one pin can usually be programed to do several different things) This is done by writing values to specific memory locations (called peripheral registers). What addresses this registers have and what the specific bits in the registers do is in the big datasheet for the device you are using. The might also be some code from the vendor (microchip in this case) that you can build on to make it easier for you.

Once everything is configured right there will be one or two registers you can read to get the actual value of the voltage at the pin. If it is a 8 bit resolution converter you will get values from 0 to 255 for a 10 bit you will have to read two register and together they will form value from 0 to 1023.

To flash the LED there is the good way and the quick and dirty way. The quick way would be to set up a timer peripheral to generate interrupts and vary the timebase based on the AD value and then write an interrupt routine that will flash the LED.

The simple way is to write a "busy loop" function (it is called busy since the cpu cant do anything else during the delay) and the number of loops is based on the AD value.

Your program would be like:

Code:
void busyLoop(int loops) {

  volatile int i;

  for(i = 0; i < loops; i++) {}
}


void main(void) {
  
  unsigned int val;
  setupAD(); 
  setupLED(); 

  while(1) {
     ledOn(); 
     val = readAD();
     busyLoop(val);
    ledOf();
    busyLoop(val);  
  }
}

Please note, this is just from the top of my head, I have never coded C for dsPIC but the basic principle is the same regardless.
All the gritty details are in the functions that you have to code yourself or "steal" :)
 
I've coded my whole motor controller in Assembly. I'm starting to wonder how usefull C is for programming
a microcontroller.

Ok, I understand C is very portable but, how portable is it really when all the registers you need to
write are microcontroller specific ?

How much advantage does C give you for performing computations ? In 30F Assembly practically everything is
16 integer, isn't this the same for the (free) C compiler ? Or does that allow floating point ? Only fixed point ?
Another advantage to C would be build in sine/cosine functions, does it have that ? These would be true advantages.

Code:
;this routine drives the motor when the time per e-revolution
;is too low. The motor will be driven by this routine until
;e-rpm rises above a certain limit and this is maintained for
;at least 7 e-revolution. The routine will then clear the drive_1
;bit, initialise for drive_2 and set the drive_2 bit.

drive_1:
;--------------------------------------- get current position and store in phi

    clr w0
    btsc PORTD, #0
    bset w0, #1
    btsc PORTD, #1
    bset w0, #2
    btsc PORTB, #4
    bset w0, #3                                           ;compute address in hall_drive_pos
    mov #hall_drive_pos, w1
    add w0, w1, w1
    mov [w1], w2                                        ;get direct_drive position
    mov w2, phi                                          ;and use for commutation

;--------------------------------------- compare new and old position pointer, update which halls flipped

    mov phi_pointer, w1                              ;get old position pointer
    mov w0, phi_pointer
                                                                ;invert phi_pointer bits
    com w0, w0
                                                                ;perform and with phi_pointer_prev -> all resulting '1's now indicate falling edge
    and w0, w1, w0
                                                                ;'or' them with halls_flipped
    ior halls_flipped

;--------------------------------------- are we too slow ? -> clear fast_rotation_counter, end
                                                                ;TMR2 overflow indicates 'too slow'
    btss IFS0, #6
    bra dr1_fast_enough

    bclr IFS0, #6
    clr fast_rotation_count
    clr halls_flipped
    bra dr1_end

;--------------------------------------- did all halls flip ? if not, end
dr1_fast_enough:

    mov #0x0E, w0
    cp halls_flipped
    bra nz, dr1_end

;--------------------------------------- reset halls_flipped and timer for next time measurement

    clr halls_flipped
    clr TMR2
    bclr IFS0, #6

;--------------------------------------- increment fast_rotation_counter

    inc fast_rotation_count

;--------------------------------------- did fast_rotation_counter reach limit ? if not: end

    mov #7, w0
    cp fast_rotation_count
    bra ltu, dr1_end

;--------------------------------------- if yes: switch to drive_2

    call initialise_drive_2

;--------------------------------------- end
dr1_end:
    return

As an example, would this assembly code be clearer when it would have been written in C ? It would have taken
less instructions but the main difficulty is in the implemented algorithm, no so much in converting the
algorithm into instructions.

This is not a plug to try to convert people to assembly, I've never used C for embedded real-time programs
and am curious whether it really has that much extra to offer. I'm really curious about whether the free C compiler
has advantages for doing fixed/floating point math and having sine/cosine ?

this is my sine/cosine routine by the way :D I was too lazy to make a full lookup table for sine/cosine and wanted
to try this algorithm :D (accuracy: +- 300 e-6 if I remember correctly)

Code:
;w0: 0-255: angle (0-359 degrees)
;based on:	sin(a+b) = sin(a) * cos(b) + cos(a) * sin(b)
;		cos(a+b) = cos(a) * cos(b) - sin(a) * sin(b)
 
sine_cosine: 
					;save registers
    push w0
    push w1
    push w2
    push w3
    push w9
    push w10                                ;sin(a+b) scratchpad
    push w11                                ;cos(a+b) scratchpad
    push w12                                ;points to sin(b) array
    push w13                                ;points to cos(b) array
					;initialise variables
    mov w0, w9
	
    mov #tblpage(sincos_b), w1
    mov w1, TBLPAG
    mov #tbloffset(sincos_b), w12
    mov #tbloffset(sincos_b)+16, w13

    mov #0x7FFF, w1
    mov w1, cos                                 ;cos (a) = 1   (at start when a=0)
    clr sin					;sin (a) = 0   (at start when a=0)
					
    do #7, sc_do_end                    ;process all 8 bits in w0
						;bit 7 = 0 ? skip multiplication
    btss w9, #7
    bra sc_skip_mult
						;multiply variables with constant if bit is set
							;w10 = sin(a) * cos(b)
    tblrdl [w13], w1                                        ;cos(b)
    mov sin, w0                                             ;sin(a)
    mul.ss w0, w1, w2                                       ;32768*x  32768*y = 65536*w3 + w2 = 32768 * ans -> ans = 2*w3
    rlc w2, w2                                              ;answer from mul.ss must be multiplied by 2 to stay in [-1..1]
    rlc w3, w10                                             ;transfer msb of w2 via carry to lsb w10
							;w10 += cos(a) * sin(b)
    tblrdl [w12], w1                                        ;sin(b)
    mov cos, w0                                             ;cos(a)
    mul.ss w0, w1, w2
    rlc w2, w2
    rlc w3, w3
    add w10, w3, w10
							;w11 = cos(a) * cos(b)
    tblrdl [w13], w1                                        ;cos(b)
    mov cos, w0                                             ;cos(a)
    mul.ss w0, w1, w2
    rlc w2, w2
    rlc w3, w11
							;w11 -= sin(a) * sin(b)
    tblrdl [w12], w1                                        ;sin(b)
    mov sin, w0                                             ;sin(a)
    mul.ss w0, w1, w2
    rlc w2, w2
    rlc w3, w3
    sub w11, w3, w11

    mov w10, sin				;sin(a)_new := sin(a+b)
    mov w11, cos				;cos(a)_new := cos(a+b)
	
sc_skip_mult:
						;rotate w9 for next bit
    sl w9, #1, w9
						;move pointer to next position in contants array
    inc2 w12, w12
sc_do_end:
    inc2 w13, w13
					;restore registers
    pop w13
    pop w12
    pop w11
    pop w10
    pop w9
    pop w3
    pop w2
    pop w1
    pop w0

    return

            .align 32
sincos_b:					;first sin(b)
            .fixed 0.0                          ;sin(360/2)
            .fixed 0.99996			;sin(360/4)
            .fixed 0.707107			;sin(360/8)
            .fixed 0.382683			;sin(360/16)
            .fixed 0.195090			;sin(360/32)
            .fixed 0.098017			;sin(360/64)
            .fixed 0.049068			;sin(360/128)
            .fixed 0.024541			;sin(360/256)
					;then cos(b), 8 (*2) addresses later
            .fixed -1.0                         ;cos(360/2)
            .fixed 0.0                          ;cos(360/4)
            .fixed 0.707107			;cos(360/8)
            .fixed 0.923880			;cos(360/16)
            .fixed 0.980785			;cos(360/32)
            .fixed 0.995185			;cos(360/64)
            .fixed 0.998795			;cos(360/128)
            .fixed 0.999699			;cos(360/256)
 
Here is a snippet. This is not all the necessary code, but part of it. Should help as I comment code a lot.

Code:
/*********************************************************************
void InitUART(void)
UART Initialization 8N1, 9600 baud, char rcv int, tx int when 1 buf free  
*********************************************************************/
void InitUART(void)  //U1TXREG   U1RXREG
{
  UART1_ATX_TRIS = 0;                 // set Alternate Tx TRIS to output
  UART1_ARX_TRIS = 1;                 // set Alternate Rx TRIS to input

  U1MODEbits.ALTIO = 1;               // Use ALT IO Pins 11-Tx 12-Rx
  U1MODEbits.PDSEL = 0x00;            // 8 bits No parity
  U1MODEbits.STSEL = 0;               // 1 stop bit

  U1STA = 0;                          // interrupt when char rcvd & when xmit buf free

  U1BRG = ((FCY/9600)/16) - 1;        // UART baud rate divisor bits 9600 baud 
                                      // U1BRG=64=(Fcy/(baudrate*16)) - 1
  U1MODEbits.UARTEN = 1;              // UART enabled
  U1STAbits.UTXEN = 1;                // Transmitter enabled

  IEC0bits.U1RXIE = 1;                // enable serial receive interrupts
//  IEC0bits.U1TXIE = 1;                // enable serial transmit interrupts
}
 
I dont want to hijack this thread with a argument of C vs ASM, there are plenty of those already. They usually come down to that in theory assembler will give you faster code and smaller footprint. However , real world constraints like engineering hours and time to market and code maintainability (how easy is it to hire C programmers vs dsPIC asm programmers?) makes higher level languages the practical choice. C is not as good but it is good enough. I work with embedded DSP software in telecoms and assembler is almost never used, not even in signal processing loops. Its all C and C++ and sometimes even code generated from UML.

A hobby project is different but if you look at a BLDC controller very little of the code is hardware dependent. Sure you have to be able to read HAL sensors or back EMF through AD converters and controll the PWM but that is all very little code if you look at the whole system. The actual algorithms is worth having portable and reusable, especially if you look into more advanced things like FOC.
 
Lebowski said:
pelle242 said:
especially if you look into more advanced but fundamentally flawed things like FOC.

fixed that for you :mrgreen:

Whatever. It was not the point... Whatever fancy genial algorithm you are implementing it will benefit from being portable and understandable, assuming you want as many people as possible to benefit from your work.
 
Thanks guys, I read 2 C programing e-books and an online beginners guide to learnign C all this weekend. I also watched some youtube videos. I am starting to find my way around. My goal is to learn something with this every time i look at it no mater how big or small. I will dig more on it tonight. But I think my problem is finding all the Microchip spesific and dspic30f spesific code info.... I have read and have had the page open on the dspic30f3010 datasheet on my computer for 2 weeks now.
Here is a list of links for thos who are in the same boat as me.
C:\Program Files (x86)\Microchip\mplabc30\v3.30c\docs\periph_lib\dsPIC30F_dsPIC33F_dsPIC33E_DCI_Library_Help.htm
http://ww1.microchip.com/downloads/en/AppNotes/BLDC%20MC%2000957a.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/70141F.pdf
http://www.cprogramming.com/tutorial.html
programing in c pdf I found on pirate bay.org
programing 16 bit microchontrollers in C learning to fly the PIC 24
 
Arlo, first of all you need to go through the entire datasheet of the chip to get a grasp at it. You don't have to read and know all of the details, but read about its architecture (usually at the beginning of the documents) and then go through more lightly on the other sections. Read "faster" the parts where they start mentioning register names on every sentence and just look once at the register descriptions. This is so that you have a general understanding of the chip and its capabilities. Post here doubts about things you read in the datasheet, usually the concepts are simple but the names don't say much (I still remember not understanding what a heck a "pre-scaler" is).

Then go back a read in more depth the parts you'll need 1st, like ADCs and general port I/O (leave PWM for later, it's usually more complex).

Then you need to know your compiler, and what libraries it has available; libraries = work done. The compiler should have documentation for what is called "the c library", a set of functions for basic things like doing delays or converting numbers to strings and vice-versa. Take a quick look through it, at least to know what modules are there, what's available, no matter the usage details - when you come to need something then you'll go back to the doc and read about that something in detail. If there's some examples even better, just copy&paste into your program - "code stealing" is the best way to program, you get code that not only is already done as it is already debugged ;)

Lebowski is an extremely good technical guy, but don't let him drag you into assembly (if Lebowski invested in C, he would go from extremely good to funkanstatically good :)). Learn C, use C, I assure you you'll thank me later :). You should focus on your project which is making a controller and not learning all the details of dsPIC & assembly. Use the fastests tools you can get your hands on.

To flash an LED at different speeds according to a throttle, you need to think in steps (as it is with all programming). You need to

1) Read the throttle position (ADC)
2) Transform the throttle position into a time delay value
3) Wait for the amount of time calculated in 2) (this will be half the time period or your flashing LED)
4) Light up your LED (port perform I/O, setting a bit)
5) Do another delay as in 3)
6) Turn off your LED
7) Go back to 1) to repeat it all over again

Now you need build or steel code to perform each of the steps above. You can dump the relevant values (like the value read from the ADC) at each step into the serial port;this will help you debug your code. Or use the step-by-step runtime debugging features or simulation features (for AVR I do lots of simulation) of your development environment, which I think your dsPIC platform has.

Ahh!, the algorithm above is the simplest you can have and some guys will come say that you shouldn't do it like this bla bla bla; just ignore them, this is an example for learning, you'll have time to optimize it with interrupts or whatever later, when you're more skilled.

Update: one more thing... you won't learn to program by reading a whole book. Just read some basics, the 1st few chapters, and them invent, program, study examples, modify them; consult books and references to get more deep into a certain subject or to see how to use specific things and help understand parts of examples. That's how we learn.

Go for it!...
 
I agree with Njay. Treat those documents as you would an encyclopedia, read the beginning so you know
a bit about the basic structure and for the rest only look over the sections you need.
 
I find that if you can get print statements to a terminal that you can usually make faster progress than simulation. Simulation is great for some really tight timing or really sticky problems, but it is very time consuming. Strategically placed printing, and conditional print statements that only print when something is interesting/problematic can speed up the debug process considerably.

Something like

make the LED blink first.

then get serial working:

printf ("hello world");

to your serial terminal.

then you can get the ADC working, read it, and print that and see that the ADC works.

and so on.

I would stick with C also. It might be a tiny bit harder to get started with than ASM, getting all the tools working and so on, but progress will be faster and bugs will be fewer and easier to find.

Good Luck!
 
Also, do like BigMoose, write lot's of comments !

Back in the day at the university the first thing they told us in C-programming class was
to first write all your comments (helps to get all your thoughts together) and only then
start with the actual program. Like the 7 steps in Njay's post, this type of comments
should be the first things you type in a new program file.
 
Lebowski said:
I've coded my whole motor controller in Assembly. I'm starting to wonder how usefull C is for programming
a microcontroller.

Ok, I understand C is very portable but, how portable is it really when all the registers you need to
write are microcontroller specific ?

How much advantage does C give you for performing computations ? In 30F Assembly practically everything is
16 integer, isn't this the same for the (free) C compiler ? Or does that allow floating point ? Only fixed point ?
Another advantage to C would be build in sine/cosine functions, does it have that ? These would be true advantages.

C is incredibly useful for programming microcontrollers. I haven't had the need to write any assembly in ages. I do a lot of Atmel AVR programming using the WinAVR GCC based compiler. You get signed and unsigned 8,16,32,and 64 bit integers 32 and 64 bit floating point, a full math/trig library, etc.

As far as portability is concerned, a good example would be my welder. It is over 12,000 lines of C. Maybe a couple hundred lines deal with registers and processor specific details (set port bit, test input pin, read the ADC, enable/disable interrupts, etc). Those all pretty much all encapsulated in hardware-specific subroutines. I guess it would take a couple of hours to port it to another completely different processor. And placing code in functions/subroutines can have zero overhead in most modern compilers since the compiler can be told to make those generate inline code with no call/return instructions.

The equivalent in hand coded assembly language would be over 100,000 lines... how long would that take to port to a different processor and get working?

My welder has a routine that is called 10,000 times a second by a hardware timer interrupt. The processor is a 16 MHz AVR. That routine does the precision timing and pulse generation. It reads the ADC, does a couple of 32 bit integer multiplies, adds, etc. and twiddles and tests several I/O port bits. All in less than 100 microseconds. Not too shabby for a 16 MHz 8 bit processor.
 
Ok guys i used the curcuit scematic that bigmoose presented and i see alot of others use another chip between the main chip and the rs232 so im wondering can i just run the dspic30f3010 to my rs232 header with the apropriate caps and resistors?
 
For rs232 a zero is -12V and a one is +12V, to make it less sensitive to interferance. Most MCUs use 0V for zero and Vcc (5 or 3.3v) for one. Something is needed to handle that. A very popular chip is the MAX232 or MAX233. If you hook it directly to your it wont work and you might fry your MCU.

Something like this is handy: http://www.ebay.com/sch/?_kw=USB%20ttl&_clu=2&_fcid=192&_localstpos=&_stpos=&gbr=1

It can be hooked directly to the MCU.
It can also be used to program infineon controllers.

If you have a mobile phone data cable they can often be moded to do the same thing.
 
pelle242 said:
For rs232 a zero is -12V and a one is +12V, to make it less sensitive to interferance. Most MCUs use 0V for zero and Vcc (5 or 3.3v) for one. Something is needed to handle that. A very popular chip is the MAX232 or MAX233. If you hook it directly to your it wont work and you might fry your MCU.

Something like this is handy: http://www.ebay.com/sch/?_kw=USB%20ttl&_clu=2&_fcid=192&_localstpos=&_stpos=&gbr=1

It can be hooked directly to the MCU.
It can also be used to program infineon controllers.

If you have a mobile phone data cable they can often be moded to do the same thing.
Im using a serial/usb converter so does this meen the converter is stepping up the 5v from the usb to 12v?
 
If it is a USB to rs232 converter yes it shouls step up to 12V. Some reservation here, +/- 12V is the rs232 spec. Some devices cheat. I know som laptops uses +/- 5v and god knows what made in china gadgets does to save a dime.

You might look into modifying your converter. If you open it is possible there are a separate chip for the TTL to 12V conversion you can remove...
 
RS-232 is actually +/- 3-15v. Less than 3v is 0, greater than 3 is is 1. Early on most PC's used 12V, so that became common. These days, many devices use 5v. USB is 5V, so your convertor is most likely 5v RS-232.
 
Back
Top