Port manipulation

Hey everyone, I'm new to this - done a few sketches of my own but I just bought an LED strip and when looking at the example sketch for it, and it works, but I can't for the life of me figure out where in this sketch it's sending data to the pins. I'm sure it's in the SendStrip() function but can't figure out exactly what line is sending data. I'm attempting to have it pulse to music and the project has been quite the challenge so far. I've spent a couple days looking at this so if anyone can offer some help I'd be immensely grateful. Thank you!

#include <avr/pgmspace.h>

// ******** DEBUG ==== should auto config to adapt different mother board *********
//#define DATA_1 (PORTF |=  0X01)    // DATA 1    // for ATMEGA
//#define DATA_0 (PORTF &=  0XFE)    // DATA 0    // for ATMEGA
//#define STRIP_PINOUT DDRF=0xFF  // for ATMEGA
#define DATA_1 (PORTC |=  0X01)    // DATA 1    // for UNO
#define DATA_0 (PORTC &=  0XFE)    // DATA 0    // for UNO
#define STRIP_PINOUT (DDRC=0xFF)    // for UNO

PROGMEM const unsigned long pattern_test_rainbow[10][10]={
  {0xff0000,0xff7f00,0xffff00,0x00ff00,0x0000ff,0x6f00ff,0x8f00ff,0x000000,0x000000,0x000000},
  {0x000000,0xff0000,0xff7f00,0xffff00,0x00ff00,0x0000ff,0x6f00ff,0x8f00ff,0x000000,0x000000},
  {0x000000,0x000000,0xff0000,0xff7f00,0xffff00,0x00ff00,0x0000ff,0x6f00ff,0x8f00ff,0x000000},
  {0x000000,0x000000,0x000000,0xff0000,0xff7f00,0xffff00,0x00ff00,0x0000ff,0x6f00ff,0x8f00ff},
  {0x8f00ff,0x000000,0x000000,0x000000,0xff0000,0xff7f00,0xffff00,0x00ff00,0x0000ff,0x6f00ff},
  {0x6f00ff,0x8f00ff,0x000000,0x000000,0x000000,0xff0000,0xff7f00,0xffff00,0x00ff00,0x0000ff},
  {0x0000ff,0x6f00ff,0x8f00ff,0x000000,0x000000,0x000000,0xff0000,0xff7f00,0xffff00,0x00ff00},
  {0x00ff00,0x0000ff,0x6f00ff,0x8f00ff,0x000000,0x000000,0x000000,0xff0000,0xff7f00,0xffff00},
  {0xffff00,0x00ff00,0x0000ff,0x6f00ff,0x8f00ff,0x000000,0x000000,0x000000,0xff0000,0xff7f00},
  {0xff7f00,0xffff00,0x00ff00,0x0000ff,0x6f00ff,0x8f00ff,0x000000,0x000000,0x000000,0xff0000},
};




// ***********************************************************************************************************
// *
// *                            Power Up Init.
// *
// *
// ***********************************************************************************************************
void setup() {                

  STRIP_PINOUT;        // set output pin - DEBUG: should auto detect which mother board for use

  reset_strip();
  //noInterrupts();

}



// ***********************************************************************************************************
// *
// *                            Main Loop 
// *
// *
// ***********************************************************************************************************
void loop() 
{

  
    send_1M_pattern(pattern_test_rainbow, 10, 70);


  /*
	frame++;
   	if(frame<=10) LEDSTRIP_PATTERN_0();
   	if(10<frame<=20) LEDSTRIP_PATTERN_0();
   	if(20<frame<=30) LEDSTRIP_PATTERN_0();
   	if(frame>30) frame=1;
   */
  //delay(1);
}


/*******************************************************************************
 * Function Name  : send_1M_pattern
 * Description    : Transmit pattern to whole 1 meter strip
 *                  
 * Input          : pointer to ROM pattern; pattern length; frame rate
 *                  
 * Output         : None
 * Return         : None
 *******************************************************************************/
void send_1M_pattern(const unsigned long data[][10], int pattern_no, int frame_rate)
{
  int i=0;
  int j=0;
  uint32_t temp_data;

  for (i=0;i<pattern_no;i++)
  {
    noInterrupts();
    for (j=0;j<10;j++)
    {
      temp_data=pgm_read_dword_near(&data[i][j]);
      send_strip(temp_data);
    }
    interrupts();

    delay(frame_rate);

  }




}


/*******************************************************************************
 * Function Name  : send_strip
 * Description    : Transmit 24 pulse to LED strip
 *                  
 * Input          : 24-bit data for the strip
 *                  
 * Output         : None
 * Return         : None
 *******************************************************************************/
void send_strip(uint32_t data)
{
  int i;
  unsigned long j=0x800000;
  
 
  for (i=0;i<24;i++)
  {
    if (data & j)
    {
      DATA_1;
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");    
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      DATA_0;
    }
    else
    {
      DATA_1;
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");    
      DATA_0;
    }

    j>>=1;
  }


  
}

/*******************************************************************************
 * Function Name  : reset_strip
 * Description    : Send reset pulse to reset all color of the strip
 *                  
 * Input          : None
 *                  
 * Output         : None
 * Return         : None
 *******************************************************************************/
void	reset_strip()
{
  DATA_0;
  delayMicroseconds(20);
}

This

void send_strip(uint32_t data)
{
  int i;
  unsigned long j=0x800000;
  
 
  for (i=0;i<24;i++)
  {
    if (data & j)
    {
      DATA_1;

is invoking the macro #defined at the top:

#define DATA_1 (PORTC |=  0X01)    // DATA 1    // for UNO

which is doing direct port manipulation on PORTC.

I see it calls it, but from what I see after it calls DATA_1 it's not passing any data to it

EDIT: is it set up so that everything between DATA_1 and DATA_0 is the data that's passed? I still only see sequences of "asm("nop\n\t");" if that's the case.. it doesn't look like the 'data' variable being passed into the function is ever sent to the pin o_O

it doesn't look like the 'data' variable being passed into the function is ever sent to the pin o_O

Yes, it is, because the value of a bit in the data variable is used to determine whether to call DATA_1 or DATA_0.

The DATA_1 and DATA_0 macros diddle specific pins on the port.

I'm assuming the asm(); is a function that sends data to the port?

And this led strip is probably sent data through rapid successions of "asm("nop\n\t");"

Is there any good way of monitoring what's being sent out of my pins so I can check my theory? I've tried simply placing serial.println() in the sendstrip functions and it won't output anything and stops the functionality of the led strip D:

soryazlawl:
I'm assuming the asm(); is a function that sends data to the port?

no, __asm__ means "I'm using C(++) in this file, but insert this section of assembly language." Assembly language is much lower level language, where every lline corresponds to one thing the microcontroller does.

nop in assembly means "Don't do anything for one clock cycle." So it's a good way to get really really tiny delays (it's like a call to the theoretical delay(62.5 nanoseconds) if you're running an arduino uno. If you have another CPU or another clock speed, it willl be a different time.)

Hmmm thank you, that makes sense. destroys my only theory as to how this program outputs data (and more importantly, what sort of data I should be passing to this led strip)

I've done quite a few ventures into programming before but this sketch is really throwing me for a loop

The pin is being set using direct port manipulation. The register that contains the pin states for a given port is called PORTC. The DATA_1 and DATA_0 macros are diddling one pin in that port.

The line you want is:

PORTC |= 0X01;

The i/O ports are memory mapped - they act just like a memory location. "PORTC" is defined as a pointer to that location somewhere in the Arduino header files.