• AVR Freaks

Helpful ReplyLockedProblems using C variables in Inline Assembler

Page: < 1234 > Showing page 2 of 4
Author
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/11 10:51:03 (permalink)
0
Holger
First I want to try it with a PIC18. Should work with assembler.
moeur
Let me know if you get it to work using assembly, and in the mean time I might give that method a try too.
Timings are guaranteed and will not change when using assembly, unlike the variations among C compiler versions.  Here's something I just threw together quick:

#include <xc.h>
#include <stdint.h>
 
#define _XTAL_FREQ  64000000UL  // Fosc = 64 MHz, Tcy = 62.5 ns
#define DIN         LATC,0      // control data signal input
 
void WS2812B(uint8_t green, uint8_t red, uint8_t blue) {
    #asm
#define lnop    bra $+2
 
        movlw   8
grn_lp: bsf     DIN
        nop
        lnop
        banksel WS2812B@green
        btfss   WS2812B@green,7
        bcf     DIN
        rlncf   WS2812B@green
        lnop
        lnop
        bcf     DIN
        lnop
        lnop
        decfsz  WREG
        bra     grn_lp
 
        movlw   8
red_lp: bsf     DIN
        bsf     STATUS,0
        lnop
        banksel WS2812B@red
        btfss   WS2812B@red,7
        bcf     DIN
        rlncf   WS2812B@red
        lnop
        lnop
        bcf     DIN
        lnop
        lnop
        decfsz  WREG
        bra     red_lp
 
blu_lp: rlcf    WREG
        bsf     DIN
        nop
        lnop
        banksel WS2812B@blue
        btfss   WS2812B@blue,7
        bcf     DIN
        rlncf   WS2812B@blue
        lnop
        lnop
        bcf     DIN
        btfsc   WREG,7
        return          // exit earlier to shorten gap between 24-bit
        lnop
        bra     blu_lp
    #endasm
}
 
void main(void)
{  
    TRISC = 0;
    __delay_us(50);
    while (1) {
        WS2812B(0x00, 0xFF, 0x55);
        WS2812B(0x01, 0x03, 0x07);
        WS2812B(0x0F, 0x1F, 0x3F);
        __delay_us(50);     // can do other things here
    }
}


 

Attached Image(s)

#21
Holger
Starting Member
  • Total Posts : 61
  • Reward points : 0
  • Joined: 2011/02/04 03:11:43
  • Location: Germany, Lake Constance
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/11 11:24:20 (permalink)
0
Hi,
thanks for the answer. If I call the method like this, I also was able to reach the right timing without delays. But then I have to call the function for each LED :-/ And there are a lot of LEDs...
 
Do u know a way to get the right timing, if using the function call like I did?
#22
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/11 13:06:12 (permalink)
0
Holger
But then I have to call the function for each LED :-/ And there are a lot of LEDs...
Use a loop, even though it will has a bigger gap between 24-bit frames.

struct CRGB {
    unsigned char g;
    unsigned char r;
    unsigned char b;
} led[10];
   
void main(void)
{
    uint8_t i;
   
    LATC = 0;
    TRISC = 0;
   
    led[9].r = 130; led[9].g =   0; led[9].b = 220;
    led[8].r =   0; led[8].g = 250; led[8].b =   0;
    led[7].r = 130; led[7].g =   0; led[7].b = 220;
    led[6].r =   0; led[6].g = 250; led[6].b =   0;
    led[5].r = 130; led[5].g =   0; led[5].b = 220;
    led[4].r =   0; led[4].g = 250; led[4].b =   0;
    led[3].r = 130; led[3].g =   0; led[3].b = 220;
    led[2].r =   0; led[2].g = 250; led[2].b =   0;
    led[1].r = 130; led[1].g =   0; led[1].b = 220;
    led[0].r =   0; led[0].g = 250; led[0].b =   0;
   
    while (1) {
        i = sizeof(led)/3 - 1;
        do
            WS2812B(led[i].g, led[i].r, led[i].b);
        while (--i);
        __delay_us(51);
    }
}

 

Do u know a way to get the right timing, if using the function call like I did?
Will take a look at your function later.  Very busy now.
 
#23
moeur
New Member
  • Total Posts : 19
  • Reward points : 0
  • Joined: 2013/09/10 00:06:50
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/12 04:39:04 (permalink)
0
I didn't realize that you were performing the actual timing with code.
Why don't you use the CCP module in PWM mode?  Set the period for 1.25 micro-seconds.
Then you have two pulse widths that you switch between depending on weather the bit value is zero (250 ns) or one (650 ns).  You do this in a tight loop that polls the associated timer's interrupt flag.
This is the approach I've been taking, but C is not quite fast enough, almost but not quite.  Perhaps if I had the Pro compiler then the optimizations would make it fast enough.  Here is the loop that needs to be optimized:
        
/* Prior to this you have filled the bitBucket[maxPixels*24] array with
* values representing the pulse widths of the associated bits.
*/       
int nbit;       
for (nbit=0;nbit < maxbits;nbit++)       
{
          while (PIR1bits.TMR2IF == 0){}  //wait for completion of this period
          PIR1bits.TMR2IF = 0; //clear the flag
          CCPR2L = bitBucket[nbit]; //load new pulse width
 }
CCPR2L = 0; //shut down PWM

 
post edited by moeur - 2013/09/12 05:20:35
#24
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/12 07:20:10 (permalink)
+1 (1)
Holger
I got it to work. I tested it sucessfully with 10 LEDs.
Are you sure?  At Fosc = 16 MHz the 0 code high time T0H (0.4 us +/- 150 ns) is 1 to 2.2 instructions in duration, and your code is a lot slower than that.

Do u know a way to get the right timing, if using the function call like I did?
See attachment.  I found a XC8 compiler bug while working on it. 
post edited by 1and0 - 2013/09/12 08:00:29
#25
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/12 07:28:04 (permalink)
0
moeur
I didn't realize that you were performing the actual timing with code.
Why don't you use the CCP module in PWM mode?  Set the period for 1.25 micro-seconds.
Then you have two pulse widths that you switch between depending on weather the bit value is zero (250 ns) or one (650 ns).  You do this in a tight loop that polls the associated timer's interrupt flag.
This is the approach I've been taking, but C is not quite fast enough, almost but not quite.  Perhaps if I had the Pro compiler then the optimizations would make it fast enough.
According to that WS2812B datasheet, you have a little bit more time -- 400 ns for zero and 800 ns for one.
#26
moeur
New Member
  • Total Posts : 19
  • Reward points : 0
  • Joined: 2013/09/10 00:06:50
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/12 10:32:43 (permalink)
0
Yes, I see.  I have the ws2812 model, I didn't even realize there was a 'B' model.
 
post edited by moeur - 2013/09/12 10:36:17
#27
moeur
New Member
  • Total Posts : 19
  • Reward points : 0
  • Joined: 2013/09/10 00:06:50
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/12 20:23:59 (permalink)
0
Since I hadn't yet used up my trial pro version of XC8 yet, I enabled it and compiled the above code I posted optimized for speed.  It works well for one or two pixels, then I think the bit bucket array gets big enough that the code to access it has to be altered and the loop can no longer run fast enough.  I don't know too much about assembly, but I'll try to learn enough to convert my above loop into a small assembly routine.
#28
moeur
New Member
  • Total Posts : 19
  • Reward points : 0
  • Joined: 2013/09/10 00:06:50
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/13 06:18:13 (permalink)
0
What do I have to do to get the xc8 compiler to recognize the #asm format?
I can use the asm() format, but if I try the other, none of the assembly commands are recognized.
 
Note that you don't have to place your function within the main while loop.  Running it once will set the color of the LEDs addressed and they will remain that way until you run the routine again with different data.
 
Still trying to get it to work, I had to convert it over to the asm() format until I learn how to use the #asm format which is much nicer (IMHO).
 
#29
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/13 08:36:26 (permalink)
+1 (1)
       
 
I don't think these RGB LEDs can be efficiently controlled with completely C code on a PIC18 device.  However, I would like to see it tried.
 
As for not using the PWM mode of the CCP module, I don't see there's any advantage.  With the maximum Fosc of 64 MHz, one bit time is about 20 instruction cycles -- that is not a lot of time to do much anything else.  Besides, storing the pulse widths (duty cycles) requires more memory.
 
Both #asm/#endasm and asm() formats work here without doing anything.  It just works.
 
#30
DarioG
Allmächtig.
  • Total Posts : 54081
  • Reward points : 0
  • Joined: 2006/02/25 08:58:22
  • Location: Oesterreich
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/13 13:03:47 (permalink)
0
Hmm, I did BAM on 24 channels, 128 steps, 200Hz circa.. in C Smile
Only the 1st BAM step is a bit critical.

GENOVA :D :D ! GODO
#31
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/13 13:20:56 (permalink)
0
DarioG
Hmm, I did BAM on 24 channels, 128 steps, 200Hz circa.. in C Smile
Only the 1st BAM step is a bit critical.
A period of 1.25 us/bit is 800 kHz.
#32
moeur
New Member
  • Total Posts : 19
  • Reward points : 0
  • Joined: 2013/09/10 00:06:50
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/13 16:04:04 (permalink)
0
@1and0
I am using your code to learn assembly.  Unfortunately I have a few problems getting it to produce the proper output on my scope.
 
I am confused about a few things
  why do you do the following?
if (length & 0xFF)              // add one to high byte of 256*loops       
length += 256;              // for fractional in the low byte

 
I see that you use WREG to count how many bits in a byte, but after the first byte you load WREG with an unrelated value and that seems to mess up the bit counting for the next byte.
next:   movf    POSTINC2            // point to next color       
      dcfsnz  WS2812B@length 0       //<-- this should load WREG with length-1 ???
      decfsz  WS2812B@length 1        
      bra     loop                // repeat for all LEDs

 
What is supposed to be going on here because on my system it gets stuck in an infinite loop.
 
#33
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/13 19:53:25 (permalink)
0
moeur
I am confused about a few things
why do you do the following?
if (length & 0xFF)              // add one to high byte of 256*loops 
length += 256;              // for fractional in the low byte

http://www.microchip.com/forums/fb.ashx?m=734819

I see that you use WREG to count how many bits in a byte, but after the first byte you load WREG with an unrelated value and that seems to mess up the bit counting for the next byte.
next:   movf    POSTINC2            // point to next color        
    dcfsnz  WS2812B@length 0       //<-- this should load WREG with length-1 ???
    decfsz  WS2812B@length 1        
    bra     loop                // repeat for all LEDs

No, those expands to
 
    dcfsnz  WS2812B@length +0
    decfsz  WS2812B@length +1
 
The LO and HI #defines are used to access <ram_address> and <ram_address>+1, respectively, to handle addressing a 16-bit variable 8 bits at a time.  They add readability.
post edited by 1and0 - 2013/09/13 19:57:34
#34
DarioG
Allmächtig.
  • Total Posts : 54081
  • Reward points : 0
  • Joined: 2006/02/25 08:58:22
  • Location: Oesterreich
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/14 00:59:14 (permalink)
0
1and0

DarioG
Hmm, I did BAM on 24 channels, 128 steps, 200Hz circa.. in C Smile
Only the 1st BAM step is a bit critical.
A period of 1.25 us/bit is 800 kHz.

 
Yeah, if I remember correctly the 1st step had only 30-40 instructions available which was at the limit for a 40/48MHz PIC18. 2nd onwards are pretty ok.
 

GENOVA :D :D ! GODO
#35
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/14 03:21:33 (permalink)
0
DarioG
Yeah, if I remember correctly the 1st step had only 30-40 instructions available which was at the limit for a 40/48MHz PIC18. 2nd onwards are pretty ok.
I'm not sure I follow you here.  I think BAM is a different thing.  If not, would you care to write a small program completely in C for a PIC18 to control a string of these WS2812B based RGB LEDs?
 
#36
moeur
New Member
  • Total Posts : 19
  • Reward points : 0
  • Joined: 2013/09/10 00:06:50
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/14 05:21:02 (permalink)
0
It works! (of course you already knew that)
Not only that but I think I understand each line.
 
Thanks
#37
DarioG
Allmächtig.
  • Total Posts : 54081
  • Reward points : 0
  • Joined: 2006/02/25 08:58:22
  • Location: Oesterreich
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/14 07:35:35 (permalink)
0

 
DarioG

Yeah, if I remember correctly the 1st step had only 30-40 instructions available which was at the limit for a 40/48MHz PIC18. 2nd onwards are pretty ok.
I'm not sure I follow you here.  I think BAM is a different thing.  If not, would you care to write a small program completely in C for a PIC18 to control a string of these WS2812B based RGB LEDs?

I was sure I had posted it in my "CML"
http://www.microchip.com/forums/tm.aspx?m=295647
but I can only see Mike's BAM basic example in there. I'll retrieve mine and post it later...
post edited by DarioG - 2013/09/14 07:39:35

GENOVA :D :D ! GODO
#38
kevcon
Super Member
  • Total Posts : 568
  • Reward points : 0
  • Joined: 2011/09/16 07:34:49
  • Location: 0
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/14 12:04:28 (permalink)
-2 (2)
Wow, that is some really tight timing you need for this part to avoid a reset condition.
post edited by kevcon - 2013/11/11 15:30:08

Go ahead, use a UNION for that, it's okay.
#39
1and0
Access is Denied
  • Total Posts : 11110
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re:Problems using C variables in Inline Assembler 2013/09/14 16:16:06 (permalink)
0
moeur
It works! (of course you already knew that)
Not only that but I think I understand each line.
Thanks
You're welcome!  That's great!  I might get some samples of these LEDs and try it.  When you get the PWM method to work, please post it here.  I'd like to see it.
#40
Page: < 1234 > Showing page 2 of 4
Jump to:
© 2020 APG vNext Commercial Version 4.5