1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Electronics PICs, Luxeons, PWM ...n00b in need of some advice!

Discussion in 'Modding' started by H2O-G33K, 11 Apr 2004.

  1. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    hmm i swear MCLR wasn't set proplery when i look *going insane smilie*
     
  2. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Hehe, well here's something that definitely is real.. my working PIC! Here we are at 2Khz PWM :

    [​IMG]

    And here it is again at 20Khz

    [​IMG]

    The pictures were taken with a 1/4s exposure and they're consistant with what i could see. I may try a few more frequencies tomorrow and see if i can get away with something lower - the lower the PWM frequency, the more cycles I'll have to do other stuff.

    Looking promising though, I think you'll agree. Thanks very much for all the help I've had getting to this point - I couldn't have done it without you all!! :thumb:
     
  3. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    If your having problems adjusting the PWM timebase (oposed to the interval) and your using my TMR0 method, easy way is not only the TMR0 pre-scaler, but also the value we set to TMR0 at the end of the ISR (interupt service routine).
     
  4. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Right now, I just wanted to test to see what the minimum useable frequency would be. If I can find out how small the maximum time the unit will be off for (low part of the PWM cycle) then I know how fast I need the base PWM frequency to be so that I don't get any flicker... that make sense?
     
  5. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Right, I took some time to go through TheAnimus's code for the PWM bits and I just wanted to check I'm following it right. Here's my commented version :

    Code:
    ORG	0x04
    
    	; Load 64 (FF-C0) into the TMR0 register so that after 64 cycles, this section of code is called again
    	MOVLW	0xC0
    	MOVWF	TMR0
    
    	CLRF	_TEMP_GPIO
    
    	; Increment our loop counter and place the result in F
    	INCF	_LOOP_COUNTER, F
    
    	; Load the loop counter into W
    	MOVF	_LOOP_COUNTER, W
    	; Add whatever's in _LED0 to W
    	ADDWF	_LED0, W
    	; If C(arry) in the status register is 0, skip the following instruction
    	; So if _LED0 + W > FF we skip the next instruction
    	BTFSC	STATUS, C
    		; set bit 0 of _TEMP_GPIO
    		BSF	_TEMP_GPIO, 0
    	; If C(arry) in the status register is 1, skip the following instruction
    	BTFSS	STATUS, C
    		; clear bit 0 of _TEMP_GPIO
    		BCF	_TEMP_GPIO, 0
    
    	; Same as the previous block, but for _LED1
    	MOVF	_LOOP_COUNTER, W
    	ADDWF	_LED1, W
    	BTFSC	STATUS, C
    		BSF	_TEMP_GPIO, 1
    	BTFSS	STATUS, C
    		BCF	_TEMP_GPIO, 1
    
    	; Same as the previous block, but for _LED2
    	MOVF	_LOOP_COUNTER, W
    	ADDWF	_LED2, W
    	BTFSC	STATUS, C
    		BSF	_TEMP_GPIO, 2
    	BTFSS	STATUS, C
    		BCF	_TEMP_GPIO, 2
    
    	; Load _TEMP_GPIO into GPIO
    	MOVF	_TEMP_GPIO, W
    	MOVWF	GPIO
    
    	; Clear the TOIF bit of INTCON
    	BCF	INTCON, T0IF
    	RETFIE
    That look about right? The only part I wasn't sure about was the 'T0IF' bit.. ?

    Now as for the timing (I'm assuming I'm running on the internal oscillator @ 8Mhz for the following calculations)... The code about executes every 64 cycles, and we're counting up to 8 bits of luminosity. 8x64 = 512 cycles for the period of one PWM cycle. 512 - 64 = 448 cycles of 'off time' between pulses, which will give a gap between pulses of 0.000224s. If I swing my Poi at ~10m/s that's going to be a gap of a little over 2.5mm between flashes (at the lowest brightness setting). I've not tested it, but I suspect that would probably be enough to be visible...

    I had a look at the code and checked the number of cycles for each instruction of your loop, which gives us the following :

    Code:
    Line      cycles          
    1       1       MOVLW   0xC0
    2       1       MOVWF   TMR0
    3       1       CLRF    _TEMP_GPIO
    4       1       INCF    _LOOP_COUNTER, F
    5       1       MOVF    _LOOP_COUNTER, W
    6       1       ADDWF   _LED0, W
    7       2       BTFSC   STATUS, C
    8       skipped         BSF
    9       2       BTFSS   STATUS, C
    10      1               BCF
    11      1       MOVF    _LOOP_COUNTER, W
    12      1       ADDWF   _LED1, W
    13      2       BTFSC   STATUS, C
    14      skipped         BSF
    15      2       BTFSS   STATUS, C
    16      1               BCF
    17      1       MOVF    _LOOP_COUNTER, W
    18      1       ADDWF   _LED2, W
    19      2       BTFSC   STATUS, C
    20      skipped         BSF
    21      2       BTFSS   STATUS, C
    22      1               BCF
    23      1       MOVF    _TEMP_GPIO, W
    24      1       MOVWF   GPIO
    25      1       BCF     INTCON, T0IF
    26      2       RETFIE  
    Total   30
    NOTE : only BCF or BSF is called so one is skipped

    That leaves ~34 cycles for my own code (how much does an interrupt use up?) right? Just wanted to double-check I've got my head around this :)
     
  6. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    okay a couple of points.

    first sorry i missed ur post yesterday, my belovied desktop, has died, the surge protector is just laffing, and the UPS, well, my farther when he decided to use my PC didn't plug it in via that. Last time i leave something there.

    Now, first off a little miss-understanding with this:
    Code:
    	; Load the loop counter into W
    	MOVF	_LOOP_COUNTER, W
    	; Add whatever's in _LED0 to W
    	ADDWF	_LED0, W
    	; If C(arry) in the status register is 0, skip the following instruction
    	; So if _LED0 + W > FF we skip the next instruction
    	BTFSC	STATUS, C
    		; set bit 0 of _TEMP_GPIO
    		BSF	_TEMP_GPIO, 0
    	; If C(arry) in the status register is 1, skip the following instruction
    	BTFSS	STATUS, C
    		; clear bit 0 of _TEMP_GPIO
    		BCF	_TEMP_GPIO, 0
    
    MOVF _LOOP_COUNTER, W
    this loads W with loop counter, which we then add a value of _LED0 too, this gives so if it overflows, cuasing the carry flag to be set, we know that (LED0 + loop counter > 0xFF) BTFSC Bit Test File, Skip [if] Clear. This means the line below is skipped if its clear (ie not set), so that means you're comment is wrong (its if NOT).

    Because we clear _TEMP_GIPIO at the top, there is no need for the second test (its already clear!).

    u said ur not sure about.
    Code:
    	; Clear the TOIF bit of INTCON
    	BCF	INTCON, T0IF
    	RETFIE
    
    In PIC interupts are exectued when the flag is set (this is checked during part of the Fetch-Execute-Decode stage) when the flag is there the ISR (Interupt Service Routine, the code at 0x04) is called.
    So first we need to clear the flag for the timer o, interupt. then retfie (which actually clears INTCON, GIEF or somthing, then return).

    Also an 8mhz PIC, will in fact only have a 2mhz instruction cycle (how long it takes to perform a instruction.
    I am sorry i am too tired to check ur maths. Maby someone else can.
    But remeber a BTFSC or similar always takes 1 instruction + the other one if true, or a NOP if its skipped. so its always at least 2 cycles (if there was a call foobar say, it would be 3 if true, 2 if false).

    hope that helps, any further problems please post, i should be fealing better tommorow and will be able to look at numbers without fealing faint!
     
  7. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    Also forgot to mention.

    We should save the STATUS, and W registers.
    thats all shown in the datasheet.

    but the idea is that way your interupt can occur anywhere in you're code and not mess it up, processing will return to the point before, and act as normal!
     
  8. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Ah yes, I see what you mean about the BTFSC section. 'So if _LED0 + W > FF we skip the next instruction' should have read 'So if _LED0 + W < FF we skip the next instruction'.

    When you say 'save the STATUS and W registers' you mean at the beginning of the ISR? ..and then restore them before we return right?

    I was aware of the 2MHz instruction cycle and the timing of the BTFSC.. I just double-checked the maths and I'm fairly sure it's right.

    Thanks very much for the help / advice - hope you're feeling better tomorrow! I'll try adding the code into my existing bits and see if I can get it working...
     
    Last edited: 31 Aug 2004
  9. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    yup dead right with the save and restore.

    also by taking out the BCF _TEMP_GPIO stanza, we save 2 precious cycles per LED!
    i only put that in the first one as a aid to understanding, little slimey cheats like this, aren't easy to follow but in this case provide us with prescious CYCLES!
     
  10. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    When I looked through the code I'd wondered if it was necessary :)

    I just programmed the chip with the latest asm file, but no joy - no lights or anything. I'm not sure about my interrupt configuring - the registers on the 18F series are not the ones you specified :

    Code:
    	BSF	INTCON, TMR0IE ; Timer0 Interupt Enable
    I think I fudged that one right, but I'm not too sure about this one particularly :

    Code:
    	MOVLW	0xC0
    	MOVWF	TMR0L
    I couldn't find the TMR0 in the documentation, but I remember reading that TRM0 could be configured as 16 or 8 bit so I guessed it'd use the low end of the 16 bit word? Do I need to specify that it's 8 bit somewhere, and if so, any idea where?

    I'm sure I've just missed something obvious, so if your machine and yourself are better tomorrow, perhaps you could take a peek for me?

    Thanks again for all the help. I feel like I'm getting somewhere - ASM is feeling more comfortable by the day! Anyways, I'm shattered now, so time for sleep for me!
     
  11. SteveyG

    SteveyG Electromodder

    Joined:
    23 Nov 2002
    Posts:
    3,049
    Likes Received:
    8
    There are several registers associated with Timer0:

    Code:
    movlw b'1100yxxx'
    movwf T0CON
    Where xxx is the prescaler value: (000 = 1:2, 111 = 1:256)
    And y sets whether a prescaler is assigned (y=0) or not (y=1).
    You have now enabled Timer0, set up Timer0 as an 8-bit timer and instructed TMR0 to increment on each internal instruction clock cycle.

    TMR0L is the Low Byte Register which you may write your TMR0 value to if you need to modify it.

    Also ensure you've set up the INTCON register to enable global and the TMR0 interrupts:

    Code:
    bsf INTCON,GIE
    bsf INTCON,TMR0IE
    Sorry I missed this thread yesterday. Don't know how :confused:
     
  12. SteveyG

    SteveyG Electromodder

    Joined:
    23 Nov 2002
    Posts:
    3,049
    Likes Received:
    8
    Also, the TMR0 flag is named differently on the 18F series of PIC's.

    Put this at the start of your ISR to preserve Working and Status regs:
    Code:
    ISR_HANDLER				
    
    
    					; FIRST PRESERVE W AND STATUS REGISTER
    
    	MOVWF 	W_TEMP      		; SAVE OFF CURRENT W REGISTER CONTENTS
    	SWAPF	STATUS,W          	; MOVE STATUS REGISTER INTO W REGISTER
    	MOVWF 	STATUS_TEMP       	; SAVE OFF CONTENTS OF STATUS REGISTER
    
    And this at the end of your ISR:
    Code:
    
    INT_EXIT					
    	BCF INTCON,TMR0IF			; RESET THE TMR0 INTERRUPT FLAG
    
    	SWAPF STATUS_TEMP,W     	; RETRIEVE COPY OF STATUS REGISTER
    	MOVWF STATUS            	; RESTORE PRE-ISR STATUS REGISTER CONTENTS
    	SWAPF W_TEMP,F
    	SWAPF W_TEMP,W          	; RESTORE PRE-ISR W REGISTER CONTENTS
    	RETFIE				; RETURN FROM INTERRUPT
    
     
  13. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    In the 18 series, TMR0, is in fact 16bit.
    mapped accross TMR0L and TMR0H so to force 8bit mode, u must set up T0CON as Stevey said.

    but more to the point, whats with:
    Code:
    	; Increment our loop counter by 32 (0x40) to give us 8 bits resolution
    	MOVLW	0x40
    	ADDWF	_LOOP_COUNTER
    ?!
    we just need to INCF _LOOP_COUNTER.

    increasing it by 40h, will make it NEVER equal 0xFF (needed for b'00000001' to caus an overflow).

    also as my code was written for a 16 series, theres no need ot bank switch (your on a 18series).
     
  14. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Okay, I'll try the settings you suggested - cheers guys.

    The odd looking code was a last minute hack I tried because I was under the impression that you ran 256*64 cycles for one PWM period (which corresponds to a gap of about 8cm if the POI's moving at 10m/s). Now since we're only using 8 bits of resolution, I thought I could speed up the whole loop by incremented 32 bits at a time.. :worried: ..Bear in mind I was pretty tired when I was trying this and I'm at work atm :miffed:, so I've not had a chance to double-check my thinking / coding.

    Does that make sense? Have I over-simplified / missed something?

    [edit]Wait, I think I might understand what you're saying.. is b'00000001' the brightest setting? If so, I think I understand why it won't work - with my method, you'd get _LOOP_COUNTER going ...192, 224, 0... so adding the LED value won't work anymore![/edit]
     
  15. SteveyG

    SteveyG Electromodder

    Joined:
    23 Nov 2002
    Posts:
    3,049
    Likes Received:
    8
    Code:
    	; Increment our loop counter by 32 (0x40) to give us 8 bits resolution
    	MOVLW	0x40
    	ADDWF	_LOOP_COUNTER
    Also, how is incrementing by 32 the same as adding 40h? :confused:


    .32 = 20h
     
  16. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    lol, must've been the windows calculator (or my fat fingers) doing something wrong.. 32(decimal) = 20(hex) ..:blush:
     
  17. TheAnimus

    TheAnimus Banned

    Joined:
    25 Dec 2003
    Posts:
    3,214
    Likes Received:
    8
    the max interval is indeed 256*64.

    If you want to reduce this, then the only number you can reduce is the 64.

    (you could take this out of the interupt, and just have it forever looping) or just whack in a 10Mhz oscillator on PLL (so it clocks at 40mhz, machine cycle 10mhz) and have it down to 1.5cm on the dimiest cycle.

    erm the b'0000 0001' is the dimmest one, because its only when _LOOP_COUNTER = 0xFF will that cuas an overflow, so thats once in every 256*64.

    second dimest is b'0000 0010', (2 in dec)
    so _LOOP_COUNTER >= 0xFE thats 255*64

    3rd dimmest is b'0000 0100' (4 in dec)
    so _LOOP_COUNTER >= 0xFC thats 253*64

    The problem with this method, is that the time base is still 256*64.
    for instnace, when u double the brightness the timebase could go to 128*64.

    If this is too slow, there is another way, but getting the code fast enough might be fun!
     
  18. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Unfortunately, I didn't have time to try your suggestions last night and I'm busy packing for a holiday next week tonight.. then holiday for a week and a course for work the week after. I'll give all this a try when I'm back from that - thanks for all the help and suggestions guys!! It's very much appreciated. :rock:
     
  19. H2O-G33K

    H2O-G33K What's a Dremel?

    Joined:
    25 Jan 2003
    Posts:
    240
    Likes Received:
    0
    Right, back from my hols - still haven't had time to try the suggestions, but while I was away I was thinking about power supplies. Whatever happens - whether I'm driving luxeons or LEDs, using PWM hardware or software, for the amount of current I'll need to drive, the pins of the PIC won't be enough. As a result, I need some sort of FETs - any suggestions? I'm not really sure what to look for?

    Also, I was wondering if using a DC-DC converter (something like this) would be a good idea to drive the PIC would be a good idea? That way, even when the voltage of the batteries drops down to say 2v, the PIC will still be able to operate.. I'm sure I've heard of people using those to drive LED torches - any idea if this would work here?

    Again, I'm wishing I'd done more electronics at A-Level :duh:

    All suggestions welcome!
     
  20. SteveyG

    SteveyG Electromodder

    Joined:
    23 Nov 2002
    Posts:
    3,049
    Likes Received:
    8
    Any NPN transistor with a gain greater than about 15, and max current of 500mA would be fine for driving a single luxeon. N-Channel MOSFET's would work fine aswell.

    Your choice of transistor isn't really critical - 2N2222A (800mA, Gain 100) would do the job fine.
     

Share This Page