Passing PORT and BIT as parameters to asm block

I'm working on modifying this project FASTER NEOPIXELS

To be able to address multiple strings of WS2812 LEDs, and have been having a terrible time of it.

I've literally spend like 5 hours researching, and I can't for the life of me get it.
instead of this...

#define PIXEL_PORT PORTB
#define PIXEL_BIT 4

sendBit(bool bitVal)
{
    asm volatile(
        "sbi %[port], %[bit] \n\t"
        ".rept %[onCycles] \n\t"
        "nop \n\t"
        ".endr \n\t"
        "cbi %[port], %[bit] \n\t"
        ".rept %[offCycles] \n\t"
        "nop \n\t"
        ".endr \n\t" ::
            [port] "I"(_SFR_IO_ADDR(PIXEL_PORT)),
        [bit] "I"(PIXEL_BIT),
        [onCycles] "I"(NS_TO_CYCLES(T1H) - 2),
        [offCycles] "I"(NS_TO_CYCLES(T1L) - 2)

    );
}

I want to do something like this.

sendBit(byte PORT, int BIT, bool bitVal)
{
    asm volatile(
        "sbi %[port], %[bit] \n\t"
        ".rept %[onCycles] \n\t"
        "nop \n\t"
        ".endr \n\t"
        "cbi %[port], %[bit] \n\t"
        ".rept %[offCycles] \n\t"
        "nop \n\t"
        ".endr \n\t" ::
            [port] "I"(_SFR_IO_ADDR(PORT)),
        [bit] "I"(BIT),
        [onCycles] "I"(NS_TO_CYCLES(T1H) - 2),
        [offCycles] "I"(NS_TO_CYCLES(T1L) - 2)

    );
}

sendBit(PORTD, 3, 1)
sendBit(PORTB, 4, 1)

Basically I want to pass PIXEL_PORT and PIXEL_BIT to sendBit's asm instead of using the definitions so that I can change the affected pin on the fly.

This is the error I get with anything I've tried.

"impossible constraint in 'asm'"

Please not that this code works as is, so I don't think the constraint code (I - 0..63) is incorrect.

Also here’s my full code.

BT_LED_CONTROLLER.ino (10.9 KB)

I don't know about passing to an assembler block, but to pass a PORT to a 'C' function you have to pass the a pointer to it. For example:

#include "Arduino.h"
void setBit(volatile uint8_t *portPtr);

void setup() {
  setBit(&PORTB);
  setBit(&PORTC);
}

void loop() {
}

void setBit(volatile uint8_t *portPtr) {
  *portPtr |= 1;
}

Ok, I simplified it based on your suggestions, no dice.

BT_LED_CONTROLLER.ino (10.8 KB)

Is there any reason you want to write your code in assembly beside to torture yourself?

So now you have to go figure out what the '_SFR_IO_ADDR' does and is it still appropriate to use it now that you're no longer using the PORTB macro.

EDIT:
FYI, it's defined in sfr_defs.h.

Maybe this will help.

&PORTB returns the 'memory' address, you need the 'IO' address.
&PORTB - __SFR_OFFSET returns the 'IO' address.
(C variable)
void SetBit( volatile uint8_t *port, uint8_t bit ) 
{
  port = port - __SFR_OFFSET;
  asm("sbi %0, %1" : : "I" (port),"I" (bit) );
}

void setup()
{
  pinMode(13,OUTPUT);
  SetBit( &PORTB, 5 ); // turn on builtin led
}

I want to do something like this.

sendBit(byte PORT, int BIT, bool bitVal) {

asm volatile(
       "sbi %[port], %[bit] \n\t"
          //etc
       "cbi %[port], %[bit] \n\t"
          // etc
  ::
           [port] "I"(_SFR_IO_ADDR(PORT)),
       [bit] "I"(BIT),
       [onCycles] "I"(NS_TO_CYCLES(T1H) - 2),
       [offCycles] "I"(NS_TO_CYCLES(T1L) - 2)

);
}
sendBit(PORTB, 4, 1)



Basically I want to pass PIXEL_PORT and PIXEL_BIT to sendBit's asm instead of using the definitions so that I can change the affected pin on the fly.

You will need more extensive changes. The SBI and CBI instructions that are being used require that the port and bit be assembly-time CONSTANTS. not passed variables that can change at run-time.
To do the equivalent on an ATmega328 would require that you read the port via a pointer, modify the desired bit, and write it out again. Something like:

   LD temp, %[ptr]    ;; register x. y. or z has pointer to correct port
   OR temp, %[bitmask] ;; set bit.  bitmask will need to be in a register
   ST %[ptr], temp    ;; write the modified byte to the port
   ;; delay
   COM %[bitmask] ;; complement bitmask for clearing bit
   AND temp. %[bitmask]
   ST %[ptr], temp ;; write bit to zero
   ;; delay

Of course, the delays will need adjusted, and you'll need to change the inline asm parameters to pass the correct kinds of arguments (a pointer register with the correct contents, and a bitmask in a register) as well.
This sort of thing is one of the reasons that digitalWrite() is so much slower than SBI/CBI in the first place. 8bit architectures get "messy" when certain values are not constants.