• AVR Freaks

Helpful ReplyHot!mixed C and assembly port manipulation

Page: < 123 Showing page 3 of 3
Author
bitdoctor
Starting Member
  • Total Posts : 26
  • Reward points : 0
  • Joined: 2019/10/11 06:10:09
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 08:20:16 (permalink)
0
1and0
Nice!  I'll see you and raise you:
void sendByte(uint8_t byte)
{
    uint8_t i = 8;
    do {
        asm("banksel sendByte@byte");
        asm("rlf     sendByte@byte");  // shift bit 7 to carry bit
        asm("banksel LATA         ");
        asm("btfsc   STATUS,0     ");  // if (carry bit == 1)
        asm("bsf     LATA & 0x7F,0");  //   750ns pulse
        asm("nop                  ");  // else
        asm("bsf     LATA & 0x7F,0");  //   250ns pulse
        asm("bcf     LATA & 0x7F,0");
    } while (--i);
}

 
Edit: Comment is added as requested.


I have started some testing. This didn't work, but the reason I uncovered is very strange. What actually happens, is that every transmitted byte equals 0x08... well, that happens to be the initialized value of loop index i. So what appears on all the Neopixels, is R=G=B=8 or a light gray, no matter what is sent. Looking at the listing, it appears that the reason is that one of the first things the compiled code does, is write the initial index value 8 into the parameter value "uint8_t byte" (location 0xF0). If you don't believe me look at line #810, here it is:
803 079B _sendByte: 
   804
   805 ;main.c: 106: uint8_t i = 8;
   806
   807 ;incstack = 0
   808 ; Regs used in _sendByte: [wreg+status,2+status,0]
   809 079B 3008 movlw 8
   810 079C 00F0 movwf ??_sendByte
   811 079D 0870 movf ??_sendByte,w
   812 079E 00F1 movwf sendByte@i
   813 079F l72:
   814 ;main.c: 107: do {
   815
   816 079F 0020 banksel sendByte@byte ;#
   817 07A0 0DF0 rlf sendByte@byte,f ;#
   818 07A1 0022 banksel 268 ;#
   819 07A2 1803 btfsc 3,0 ;#
   820 07A3 140C bsf 12,0 ;#
   821 07A4 0000 nop ;#
   822 07A5 140C bsf 12,0 ;#
   823 07A6 100C bcf 12,0 ;#
   824
   825 ;main.c: 116: } while (--i);
   826 07A7 3001 movlw 1
   827 07A8 02F1 subwf sendByte@i,f
   828 07A9 1903 btfsc 3,2
   829 07AA 0008 return
   830 07AB 2F9F goto l72
   831 07AC __end_of_sendByte:

post edited by bitdoctor - 2019/10/17 08:41:32
#41
pcbbc
Super Member
  • Total Posts : 1384
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 08:54:49 (permalink)
+1 (1)
Yep, the compiler is confused.  Probably because it thinks you aren't using byte which is passed in in the W register.  Therefore it doesn't bother preserving it.
 
Try...

 
void sendByte(uint8_t byte)
{
    volatile uint8_t temp = byte;
    uint8_t i = 8;
    do {
        asm("banksel sendByte@temp");
        asm("rlf     sendByte@temp");  // shift bit 7 to carry bit
        asm("banksel LATA         ");
        asm("btfsc   STATUS,0     ");  // if (carry bit == 1)
        asm("bsf     LATA & 0x7F,0");  //   750ns pulse
        asm("nop                  ");  // else
        asm("bsf     LATA & 0x7F,0");  //   250ns pulse
        asm("bcf     LATA & 0x7F,0");
    } while (--i);
}

post edited by pcbbc - 2019/10/17 09:01:44
#42
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:12:44 (permalink)
+1 (1)
Pcbbc is correct. The compiler allocates ??_sendByte and sendByte@byte to the same RAM location. His snippet will work but it is bloated.  This is more efficient:
void sendByte(uint8_t byte)
{
    uint8_t i;
    i = 0; i |= 8;
        asm("banksel LATA         ");
    do {
        asm("rlf     WREG         ");  // shift bit 7 to carry bit
        asm("btfsc   STATUS,0     ");  // if (carry bit == 1)
        asm("bsf     LATA & 0x7F,0");  //   750ns pulse
        asm("nop                  ");  // else
        asm("bsf     LATA & 0x7F,0");  //   250ns pulse
        asm("bcf     LATA & 0x7F,0");
    } while (--i);
}
 
post edited by 1and0 - 2019/10/17 09:14:40
#43
pcbbc
Super Member
  • Total Posts : 1384
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:28:07 (permalink)
0
Except that...
while (--i);

...clobbers the W register (at least in free mode):
17:                } while (--i);
07F9  3001     MOVLW 0x1
07FA  02F3     SUBWF i, F
07FB  1903     BTFSC STATUS, 0x2
07FC  0008     RETURN
07FD  2FF1     GOTO 0x7F1

Edit: Yes, I realise the compiler could use a DECFSZ and thereby preserve W.  But it looks like you'll have to hand code the loop in assembler if you want that.
post edited by pcbbc - 2019/10/17 09:30:53
#44
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:31:52 (permalink)
0
Stupid compiler!!! mr green: mr green
#45
bitdoctor
Starting Member
  • Total Posts : 26
  • Reward points : 0
  • Joined: 2019/10/11 06:10:09
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:41:41 (permalink)
0
Since the last post, I've discovered another serious problem... code in reply #19 and #24 does work with SK6812's but not with WS2812's. That means that the refinements of that code that follow, likely won't work with WS2812's either. That probably means that my original clumsy code also only works with SK6812.
 
It doesn't surprise me that timing which doesn't meet the specs doesn't work... however I am puzzled that the detailed blog explanations expressing latitude in the timing of T0L and T1L appear to be false. It is possible that those people were working with different silicon implementations in the same package. I can't tell whether I have WS2812 or WS2812B's because they are sourced anonymously - I guess that could be it. At least, everything they say appears to be true of the SK6812 (at least the ones I have).
post edited by bitdoctor - 2019/10/17 09:49:02
#46
pcbbc
Super Member
  • Total Posts : 1384
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:44:18 (permalink)
0
1and0
Stupid compiler!!! mr green: mr green

Yep - Not great on this occasion.
 
Also I'm wondering what happens if the local loop variable "i" is not placed in the common RAM by the compiler?  Is it clever enough to do a BANKSEL again as part of the "while"?  If it does, then okay.  But then hoisting the "banksel LATA" out of the loop, as you have done, will break it.
 
More then ever I am convinced that using in-line assembler is fraught will all kinds of gotchas on 8-bit PIC devices.
#47
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:46:43 (permalink)
0
bitdoctor
Since the last post, I've discovered another serious problem... code in reply #19 and #24 does work with SK6812's but not with WS2812's. That means that the refinements of that code that follow, likely won't work with WS2812's either. That probably means that my original clumsy code also only works with SK6812.

Try slowing it down by adding NOP.
#48
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:48:48 (permalink)
0
pcbbc
Yep - Not great on this occasion.
 
Also I'm wondering what happens if the local loop variable "i" is not placed in the common RAM by the compiler?  Is it clever enough to do a BANKSEL again as part of the "while"?  If it does, then okay.  But then hoisting the "banksel LATA" out of the loop, as you have done, will break it.
 
More then ever I am convinced that using in-line assembler is fraught will all kinds of gotchas on 8-bit PIC devices.

No way the brain-dead compiler can mess this one up ;)  LOL
void sendByte(uint8_t byte)
{
    volatile uint8_t i = 0;
    asm("        bsf     sendByte@i,3 ");
    asm("loop:   banksel LATA         ");
    asm("        rlf     WREG         ");  // shift bit 7 to carry bit
    asm("        btfsc   STATUS,0     ");  // if (carry bit == 1)
    asm("        bsf     LATA & 0x7F,0");  //   750ns pulse
    asm("        nop                  ");  // else
    asm("        bsf     LATA & 0x7F,0");  //   250ns pulse
    asm("        bcf     LATA & 0x7F,0");
    asm("        banksel sendByte@i   ");
    asm("        decfsz  sendByte@i   ");
    asm("        bra     loop         ");
}

post edited by 1and0 - 2019/10/17 10:01:43
#49
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 09:55:25 (permalink)
0
Or this:
void sendByte(uint8_t byte)
{
    volatile uint8_t i = 0;
    asm("        bsf     sendByte@i,3 ");
    asm("loop:   banksel LATA         ");
    asm("        btfsc   WREG,7       ");  // if (bit7 == 1)
    asm("        bsf     LATA & 0x7F,0");  //   750ns pulse
    asm("        rlf     WREG         ");  // else
    asm("        bsf     LATA & 0x7F,0");  //   250ns pulse
    asm("        bcf     LATA & 0x7F,0");
    asm("        banksel sendByte@i   ");
    asm("        decfsz  sendByte@i   ");
    asm("        bra     loop         ");
}

post edited by 1and0 - 2019/10/17 10:08:50
#50
bitdoctor
Starting Member
  • Total Posts : 26
  • Reward points : 0
  • Joined: 2019/10/11 06:10:09
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 10:57:55 (permalink)
0
The previous post, #50, works with the SK6812 but not the WS2812. The time between the falling edge of T0H and the rising edge of T0H (ostensibly T0L) is 2250ns. Previously, lengthening T0L and T1L has had no effect on the SK6812. Lengthening T0H will exceed the spec, lengthening T1H won't so I could try it, but my hopes are not high for inserting NOP's.
 
I think that T0L or T1L is already too long for the WS2812. Again, I have no idea why it worked for "Josh".
 
With this code, T1H+T1L = 3000ns and T0H+T0L = 2000ns. To meet WS2812B spec, TH+TL must be less than 1250+600=1850ns. It almost makes it.
post edited by bitdoctor - 2019/10/17 11:22:58

Attached Image(s)

#51
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 11:42:17 (permalink)
+1 (1)
Here are the data time in ns:
 
              WS2812        WS2812B       SK6812
T0H (ns)    150 -  450    250 -  550    200 - 500
T1H (ns)    450 -  750    650 -  950    550 - 850
T0L (ns)    750 - 1050    700 - 1000    650 - 950
T1L (ns)    450 -  750    300 -  600    450 - 750
 
TH + TL = 1250 ± 600 ns
#52
dan1138
Super Member
  • Total Posts : 3290
  • Reward points : 0
  • Joined: 2007/02/21 23:04:16
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 13:30:36 (permalink)
0
@bitdoctor,

Please give this a try code in your setup.
/*
 * File:   main.c
 * Author: dan1138
 * Target: PIC16F1512
 *
 * Created on October 17, 2019, 1:22 PM
 *
 *                             PIC16F1512
 *                  +-------------:_:-------------+
 *        VPP ->  1 : RE3/MCLR/VPP        PGD/RB7 : 28 <> PGD
 *   Neopixel <-  2 : RA0/AN0             PGC/RB6 : 27 <> PGC
 *            <>  3 : RA1/AN1        T1G/AN13/RB5 : 26 <>
 *            <>  4 : RA2/AN2            AN11/RB4 : 25 <>
 *            <>  5 : RA3/AN3             AN9/RB3 : 24 <>
 *            <>  6 : RA4/T0CKI           AN8/RB2 : 23 <>
 *            <>  7 : RA5/AN4            AN10/RB1 : 22 <>
 *        GND ->  8 : VSS            INT/AN12/RB0 : 21 <>
 *            <>  9 : RA7/OSC1                VDD : 20 <- 5v0
 *            <> 10 : RA6/OSC2                VSS : 19 <- GND
 *            <> 11 : RC0/SOSCO      RXD/AN19/RC7 : 18 <>
 *            <> 12 : RC1/SOSCI/CCP2 TXD/AN18/RC6 : 17 <>
 *            <> 13 : RC2/AN14/CCP1  SDO/AN17/RC5 : 16 <>
 *            <> 14 : RC3/AN15/SCK   SDI/AN16/RC4 : 15 <>
 *                  +-----------------------------:
 *                              DIP-28
 *
 * Description:
 *
 *  Demo code that "may" write to a string of 27 neopixels.
 *
 *  Note: Tested only with the MPLABX simulator, and you know what that means.
 */
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable bit (VCAP pin function disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

#include <xc.h>
#include <stdint.h>

#define _XTAL_FREQ (16000000ul)
/*
 * Initialize this PIC
 */
void PIC_Init(void)
{
    INTCON = 0;
    OSCCON = 0b01111010;    /* Select internal 16MHz oscillator */
    
    ANSELA = 0b11111110;    /* Make RA0 a digital output */
    TRISA  = 0b11111110;
    LATA   = 0b11111111;
}
/*
 * Update pixels
 */
typedef struct{
    uint8_t Red;   /* The order may be different with your neopixel */
    uint8_t Blue;
    uint8_t Green;
} Pixel_t;
/*
 * This implementation uses 6 instruction cycles per bit cell
 * to send 24 bits.
 *
 * A zero bit is a high pulse of one instruction cycle,
 * followed by a low of five instruction cycles.
 *
 * A one bit is a high pulse of three instruction cycles,
 * followed by a low of three instruction cycles.
 *
 * The last bit of a 3 byte groups has the low period
 * extended by two instruction cycles.
 */
void SendNeopixels(Pixel_t *pPixels, uint8_t Pixels)
{
    FSR0 = (volatile unsigned short)pPixels;
    LATAbits.LATA0 = 0;
    __delay_us(100);
    WREG = Pixels;
    __asm(" banksel LATA\n");
    __asm("SendLoop:     btfsc INDF0,7\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,6\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,5\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,4\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,3\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,2\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,1\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,0\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");

    __asm(" addfsr 0,1\n btfsc INDF0,7\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,6\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,5\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,4\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,3\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,2\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,1\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,0\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");

    __asm(" addfsr 0,1\n btfsc INDF0,7\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,6\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,5\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,4\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,3\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,2\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,1\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" nop\n        btfsc INDF0,0\n bsf PORTA,0\n nop\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" addfsr  0,1");
    __asm(" decfsz WREG,F");
    __asm(" bra SendLoop");
}
/*
 * Pixel structure
 */
Pixel_t Buffer[27];
/*
 * Application loop
 */
void main(void)
{
    uint8_t Index;
    
    PIC_Init();
    
    for(Index = 0; Index < sizeof(Buffer)/sizeof(*Buffer); Index++)
    {
        Buffer[Index].Red   = 127; /* Who know what color this might be */
        Buffer[Index].Blue  = 63;  /* should be red-bluish green. */
        Buffer[Index].Green = 31;
    }
    for(;;)
    {
        SendNeopixels(Buffer, sizeof(Buffer)/sizeof(*Buffer));
        NOP();
    }
}

post edited by dan1138 - 2019/10/17 13:33:11
#53
bitdoctor
Starting Member
  • Total Posts : 26
  • Reward points : 0
  • Joined: 2019/10/11 06:10:09
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 13:48:04 (permalink)
0
dan1138
@bitdoctor,

Please give this a try code in your setup.



Done. Works with the SK6812's but not the WS2812's
#54
dan1138
Super Member
  • Total Posts : 3290
  • Reward points : 0
  • Joined: 2007/02/21 23:04:16
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 13:56:58 (permalink)
0
Based on table from post #52:
/*
              WS2812        WS2812B       SK6812
T0H (ns)    150 -  450    250 -  550    200 - 500
T1H (ns)    450 -  750    650 -  950    550 - 850
T0L (ns)    750 - 1050    700 - 1000    650 - 950
T1L (ns)    450 -  750    300 -  600    450 - 750
 
TH + TL = 1250 ± 600 ns
*/

These are the system oscillator frequencies that would be ideal for the code in post #53:
/*
WS2812  FOSC = 13.333 MHz
WS2812B FOSC = 10.000 MHz
SK6812  FOSC = 11.428 MHz
*/

#55
dan1138
Super Member
  • Total Posts : 3290
  • Reward points : 0
  • Joined: 2007/02/21 23:04:16
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 19:28:46 (permalink)
0
@bitdoctor,

Please give this a try code in your setup with a 13MHz crystal and the WS2812.
/*
 * File:   main.c
 * Author: dan1138
 * Target: PIC16F1512
 *
 * Created on October 17, 2019, 7:14 PM
 *
 *                             PIC16F1512
 *                  +-------------:_:-------------+
 *        VPP ->  1 : RE3/MCLR/VPP        PGD/RB7 : 28 <> PGD
 *   Neopixel <-  2 : RA0/AN0             PGC/RB6 : 27 <> PGC
 *            <>  3 : RA1/AN1        T1G/AN13/RB5 : 26 <>
 *            <>  4 : RA2/AN2            AN11/RB4 : 25 <>
 *            <>  5 : RA3/AN3             AN9/RB3 : 24 <>
 *            <>  6 : RA4/T0CKI           AN8/RB2 : 23 <>
 *            <>  7 : RA5/AN4            AN10/RB1 : 22 <>
 *        GND ->  8 : VSS            INT/AN12/RB0 : 21 <>
 *     13 MHZ ->  9 : RA7/OSC1                VDD : 20 <- 5v0
 *     13 MHz <- 10 : RA6/OSC2                VSS : 19 <- GND
 *            <> 11 : RC0/SOSCO      RXD/AN19/RC7 : 18 <>
 *            <> 12 : RC1/SOSCI/CCP2 TXD/AN18/RC6 : 17 <>
 *            <> 13 : RC2/AN14/CCP1  SDO/AN17/RC5 : 16 <>
 *            <> 14 : RC3/AN15/SCK   SDI/AN16/RC4 : 15 <>
 *                  +-----------------------------:
 *                              DIP-28
 *
 * Description:
 *
 *  Demo code that "may" write to a string of 27 neopixels.
 *
 *  Note: Tested only with the MPLABX simulator, and you know what that means.
 */
#pragma config FOSC = HS        // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable bit (VCAP pin function disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

#include <xc.h>
#include <stdint.h>

#define _XTAL_FREQ (13000000ul)
/*
 * Initialize this PIC
 */
void PIC_Init(void)
{
    INTCON = 0;
    OSCCON = 0b01111000;    /* Select external 13MHz oscillator */
    
    ANSELA = 0b11111110;    /* Make RA0 a digital output */
    TRISA  = 0b11111110;
    LATA   = 0b11111111;
}
/*
 * Update pixels
 */
typedef struct{
    uint8_t Red;   /* The order may be different with your neopixel */
    uint8_t Blue;
    uint8_t Green;
} Pixel_t;
/*
 * This implementation uses 5 instruction cycles per bit cell
 * to send 24 bits.
 *
 * A zero bit is a high pulse of one instruction cycle,
 * followed by a low of four instruction cycles.
 *
 * A one bit is a high pulse of three instruction cycles,
 * followed by a low of two instruction cycles.
 *
 * The last bit of a 3 byte groups has the low period
 * extended by two instruction cycles.
 */
void SendNeopixels(Pixel_t *pPixels, uint8_t Pixels)
{
    FSR0 = (volatile unsigned short)pPixels;
    LATAbits.LATA0 = 0;
    __delay_us(100);
    WREG = Pixels;
    __asm(" banksel LATA\n");
    __asm("SendLoop:     btfsc INDF0,7\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,6\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,5\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,4\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,3\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,2\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,1\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,0\n bsf PORTA,0\n addfsr 0,1\n bsf PORTA,0\n bcf PORTA,0\n");

    __asm("              btfsc INDF0,7\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,6\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,5\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,4\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,3\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,2\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,1\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,0\n bsf PORTA,0\n addfsr 0,1\n bsf PORTA,0\n bcf PORTA,0\n");

    __asm("              btfsc INDF0,7\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,6\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,5\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,4\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,3\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,2\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,1\n bsf PORTA,0\n nop\n        bsf PORTA,0\n bcf PORTA,0\n");
    __asm("              btfsc INDF0,0\n bsf PORTA,0\n addfsr 0,1\n bsf PORTA,0\n bcf PORTA,0\n");
    __asm(" decfsz WREG,F");
    __asm(" bra SendLoop");
}
/*
 * Pixel structure
 */
Pixel_t Buffer[27];
/*
 * Application loop
 */
void main(void)
{
    uint8_t Index;
    
    PIC_Init();
    
    for(Index = 0; Index < sizeof(Buffer)/sizeof(*Buffer); Index++)
    {
        Buffer[Index].Red   = 127; /* Who know what color this might be */
        Buffer[Index].Blue  = 63;  /* should be red-bluish green. */
        Buffer[Index].Green = 31;
    }
    for(;;)
    {
        SendNeopixels(Buffer, sizeof(Buffer)/sizeof(*Buffer));
        NOP();
    }
}

#56
bitdoctor
Starting Member
  • Total Posts : 26
  • Reward points : 0
  • Joined: 2019/10/11 06:10:09
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 19:30:44 (permalink)
0
You can get a baud rate (I think) 11.0592MHz crystal. Its fairly common.
#57
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/17 20:53:10 (permalink)
0
Here is a thread that might be of interest: https://www.microchip.com/forums/m744144-p2.aspx
#58
davea
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2016/01/28 13:12:13
  • Location: 0
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/18 17:06:01 (permalink)
0
 
is there a reason you are using PORTA and not LATA
when everyone else uses LATA 
#59
1and0
Access is Denied
  • Total Posts : 10000
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: mixed C and assembly port manipulation 2019/10/18 17:23:33 (permalink)
+2 (2)
davea
is there a reason you are using PORTA and not LATA
when everyone else uses LATA 

He uses PORTA to avoid the compiler's warning regarding truncation to 7 bits. The bank is selected for LATA, so it will access LATA and not PORTA.
 
Edit: However, it will not be "portable"; i.e. it will not work as intended on the newer enhanced midrange devices, where both PORTA and LATA are located in the same bank.
post edited by 1and0 - 2019/10/18 17:31:50
#60
Page: < 123 Showing page 3 of 3
Jump to:
© 2019 APG vNext Commercial Version 4.5